mirror of https://github.com/libsdl-org/SDL.git
Merge branch 'main' into patch-1
This commit is contained in:
commit
9eceae33ac
|
|
@ -113,7 +113,8 @@ JOB_SPECS = {
|
|||
"msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ),
|
||||
"ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ),
|
||||
"ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ),
|
||||
"steamrt-sniper": JobSpec(name="Steam Linux Runtime (Sniper)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-slrsniper", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta", ),
|
||||
"steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ),
|
||||
"steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:3.0.20250408.124536", ),
|
||||
"ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
|
||||
"ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ),
|
||||
"macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ),
|
||||
|
|
|
|||
|
|
@ -1736,6 +1736,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
|||
sdl_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_dbus.c"
|
||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_system_theme.c"
|
||||
"${SDL3_SOURCE_DIR}/src/core/linux/SDL_progressbar.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ my $wikiurl = 'https://wiki.libsdl.org';
|
|||
my $bugreporturl = 'https://github.com/libsdl-org/sdlwiki/issues/new';
|
||||
my $srcpath = undef;
|
||||
my $wikipath = undef;
|
||||
my $wikireadmesubdir = 'README';
|
||||
my $warn_about_missing = 0;
|
||||
my $copy_direction = 0;
|
||||
my $optionsfname = undef;
|
||||
|
|
@ -427,6 +426,7 @@ sub dewikify_chunk {
|
|||
# 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.
|
||||
|
|
@ -1033,7 +1033,6 @@ sub generate_quickref {
|
|||
my $incpath = "$srcpath";
|
||||
$incpath .= "/$incsubdir" if $incsubdir ne '';
|
||||
|
||||
my $wikireadmepath = "$wikipath/$wikireadmesubdir";
|
||||
my $readmepath = undef;
|
||||
if (defined $readmesubdir) {
|
||||
$readmepath = "$srcpath/$readmesubdir";
|
||||
|
|
@ -2082,18 +2081,15 @@ if ($copy_direction == 1) { # --copy-to-headers
|
|||
}
|
||||
|
||||
if (defined $readmepath) {
|
||||
if ( -d $wikireadmepath ) {
|
||||
mkdir($readmepath); # just in case
|
||||
opendir(DH, $wikireadmepath) or die("Can't opendir '$wikireadmepath': $!\n");
|
||||
while (readdir(DH)) {
|
||||
my $dent = $_;
|
||||
if ($dent =~ /\A(.*?)\.md\Z/) { # we only bridge Markdown files here.
|
||||
next if $1 eq 'FrontPage';
|
||||
filecopy("$wikireadmepath/$dent", "$readmepath/README-$dent", "\n");
|
||||
}
|
||||
mkdir($readmepath); # just in case
|
||||
opendir(DH, $wikipath) or die("Can't opendir '$wikipath': $!\n");
|
||||
while (readdir(DH)) {
|
||||
my $dent = $_;
|
||||
if ($dent =~ /\AREADME\-.*?\.md\Z/) { # we only bridge Markdown files here that start with "README-".
|
||||
filecopy("$wikipath/$dent", "$readmepath/$dent", "\n");
|
||||
}
|
||||
closedir(DH);
|
||||
}
|
||||
closedir(DH);
|
||||
}
|
||||
|
||||
} elsif ($copy_direction == -1) { # --copy-to-wiki
|
||||
|
|
@ -2698,31 +2694,27 @@ __EOF__
|
|||
# Write out READMEs...
|
||||
if (defined $readmepath) {
|
||||
if ( -d $readmepath ) {
|
||||
mkdir($wikireadmepath); # just in case
|
||||
mkdir($wikipath); # just in case
|
||||
opendir(DH, $readmepath) or die("Can't opendir '$readmepath': $!\n");
|
||||
while (my $d = readdir(DH)) {
|
||||
my $dent = $d;
|
||||
if ($dent =~ /\AREADME\-(.*?\.md)\Z/) { # we only bridge Markdown files here.
|
||||
my $wikifname = $1;
|
||||
next if $wikifname eq 'FrontPage.md';
|
||||
filecopy("$readmepath/$dent", "$wikireadmepath/$wikifname", "\n");
|
||||
if ($dent =~ /\AREADME\-.*?\.md\Z/) { # we only bridge Markdown files here that start with "README-".
|
||||
filecopy("$readmepath/$dent", "$wikipath/$dent", "\n");
|
||||
}
|
||||
}
|
||||
closedir(DH);
|
||||
|
||||
my @pages = ();
|
||||
opendir(DH, $wikireadmepath) or die("Can't opendir '$wikireadmepath': $!\n");
|
||||
opendir(DH, $wikipath) or die("Can't opendir '$wikipath': $!\n");
|
||||
while (my $d = readdir(DH)) {
|
||||
my $dent = $d;
|
||||
if ($dent =~ /\A(.*?)\.(mediawiki|md)\Z/) {
|
||||
my $wikiname = $1;
|
||||
next if $wikiname eq 'FrontPage';
|
||||
push @pages, $wikiname;
|
||||
if ($dent =~ /\A(README\-.*?)\.md\Z/) {
|
||||
push @pages, $1;
|
||||
}
|
||||
}
|
||||
closedir(DH);
|
||||
|
||||
open(FH, '>', "$wikireadmepath/FrontPage.md") or die("Can't open '$wikireadmepath/FrontPage.md': $!\n");
|
||||
open(FH, '>', "$wikipath/READMEs.md") or die("Can't open '$wikipath/READMEs.md': $!\n");
|
||||
print FH "# All READMEs available here\n\n";
|
||||
foreach (sort @pages) {
|
||||
my $wikiname = $_;
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ flags to the compiler.
|
|||
- Use [`CMAKE_EXE_LINKER_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXE_LINKER_FLAGS.html) to pass extra option to the linker for executables.
|
||||
- Use [`CMAKE_SHARED_LINKER_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_LINKER_FLAGS.html) to pass extra options to the linker for shared libraries.
|
||||
|
||||
#### Examples
|
||||
#### Compile Options Examples
|
||||
|
||||
- build a SDL library optimized for (more) modern x64 microprocessor architectures.
|
||||
|
||||
|
|
@ -240,7 +240,7 @@ Append with a version number to target a specific SDK revision: e.g. `iphoneos12
|
|||
|
||||
CMake documentation: [link](https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_SYSROOT.html)
|
||||
|
||||
#### Examples
|
||||
#### Apple Examples
|
||||
|
||||
- for macOS, building a dylib and/or static library for x86_64 and arm64:
|
||||
|
||||
|
|
|
|||
|
|
@ -327,6 +327,16 @@ If you add Doxygen with a `##` (`###`, etc) section header, it'll
|
|||
migrate to the wiki and be _removed_ from the headers. Generally
|
||||
the correct thing to do is _never use section headers in the Doxygen_.
|
||||
|
||||
## wikiheaders will reorder standard sections.
|
||||
|
||||
The standard sections are always kept in a consistent order by
|
||||
wikiheaders, both in the headers and the wiki. If they're placed in
|
||||
a non-standard order, wikiheaders will reorder them.
|
||||
|
||||
For sections that aren't standard, wikiheaders will place them at
|
||||
the end of the wiki page, in the order they were seen when it loaded
|
||||
the page for processing.
|
||||
|
||||
## It's okay to repeat yourself.
|
||||
|
||||
Each individual piece of documentation becomes a separate page on the wiki, so
|
||||
|
|
@ -340,7 +350,7 @@ through, header users can search for the function name.
|
|||
|
||||
You might be reading this document on the wiki! Any `README-*.md` files in
|
||||
the docs directory are bridged to the wiki, so `docs/README-linux.md` lands
|
||||
at https://wiki.libsdl.org/SDL3/README/linux ...these are just copied directly
|
||||
at https://wiki.libsdl.org/SDL3/README-linux ...these are just copied directly
|
||||
without any further processing by wikiheaders, and changes go in both
|
||||
directions.
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ getting started.
|
|||
|
||||
Another option is to use SDL' main callbacks, which handle this for you
|
||||
without platform-specific code in your app. Please refer to
|
||||
[the wiki](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3)
|
||||
[the wiki](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3)
|
||||
or `docs/README-main-functions.md` in the SDL source code.
|
||||
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ tools.
|
|||
mkdir build
|
||||
cd build
|
||||
emcmake cmake ..
|
||||
# you can also do `emcmake cmake -G Ninja ..` and then use `ninja` instead of this command.
|
||||
# you can also try `emcmake cmake -G Ninja ..` and then use `ninja` instead of this command.
|
||||
emmake make -j4
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ SDL3 has been known to work on the following platforms at some point:
|
|||
- [macOS](README-macos.md) (10.14 and later)
|
||||
- [NetBSD](README-bsd.md)
|
||||
- [Nintendo Switch](README-switch.md) (Separate NDA-only fork)
|
||||
- [Nintendo 3DS](README-3ds.md) (Homebrew)
|
||||
- [Nintendo 3DS](README-n3ds.md) (Homebrew)
|
||||
- [OpenBSD](README-bsd.md)
|
||||
- [PlayStation 2](README-ps2.md) (Homebrew)
|
||||
- [PlayStation 4](README-ps4.md) (Separate NDA-only fork)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,15 @@ encounter limitations or behavior that is different from other windowing systems
|
|||
`SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
|
||||
application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
|
||||
|
||||
### The application progress bar can't be set via ```SDL_SetWindowProgressState()``` or ```SDL_SetWindowProgressValue()```
|
||||
|
||||
- Only some Desktop Environemnts support the underlying API. Known compatible DEs: Unity, KDE
|
||||
- The underlying API requires a desktop entry file, aka a `.desktop` file.
|
||||
Please see the [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/) for
|
||||
more information on the format of this file. Note that if your application manually sets the application ID via the
|
||||
`SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
|
||||
application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
|
||||
|
||||
### Keyboard grabs don't work when running under XWayland
|
||||
|
||||
- On GNOME based desktops, the dconf setting `org/gnome/mutter/wayland/xwayland-allow-grabs` must be enabled.
|
||||
|
|
|
|||
|
|
@ -781,7 +781,7 @@ typedef struct SDL_TouchFingerEvent
|
|||
} SDL_TouchFingerEvent;
|
||||
|
||||
/**
|
||||
* Pressure-sensitive pen proximity event structure (event.pmotion.*)
|
||||
* Pressure-sensitive pen proximity event structure (event.pproximity.*)
|
||||
*
|
||||
* When a pen becomes visible to the system (it is close enough to a tablet,
|
||||
* etc), SDL will send an SDL_EVENT_PEN_PROXIMITY_IN event with the new pen's
|
||||
|
|
|
|||
|
|
@ -206,8 +206,10 @@
|
|||
* underlying graphics API. While it's possible that we have done something
|
||||
* inefficiently, it's very unlikely especially if you are relatively
|
||||
* inexperienced with GPU rendering. Please see the performance tips above and
|
||||
* make sure you are following them. Additionally, tools like RenderDoc can be
|
||||
* very helpful for diagnosing incorrect behavior and performance issues.
|
||||
* make sure you are following them. Additionally, tools like
|
||||
* [RenderDoc](https://renderdoc.org/)
|
||||
* can be very helpful for diagnosing incorrect behavior and performance
|
||||
* issues.
|
||||
*
|
||||
* ## System Requirements
|
||||
*
|
||||
|
|
@ -333,6 +335,39 @@
|
|||
* unreferenced data in a bound resource without cycling, but overwriting a
|
||||
* section of data that has already been referenced will produce unexpected
|
||||
* results.
|
||||
*
|
||||
* ## Debugging
|
||||
*
|
||||
* At some point of your GPU journey, you will probably encounter issues that
|
||||
* are not traceable with regular debugger - for example, your code compiles
|
||||
* but you get an empty screen, or your shader fails in runtime.
|
||||
*
|
||||
* For debugging such cases, there are tools that allow visually inspecting
|
||||
* the whole GPU frame, every drawcall, every bound resource, memory buffers,
|
||||
* etc. They are the following, per platform:
|
||||
*
|
||||
* * For Windows/Linux, use
|
||||
* [RenderDoc](https://renderdoc.org/)
|
||||
* * For MacOS (Metal), use Xcode built-in debugger (Open XCode, go to Debug >
|
||||
* Debug Executable..., select your application, set "GPU Frame Capture" to
|
||||
* "Metal" in scheme "Options" window, run your app, and click the small
|
||||
* Metal icon on the bottom to capture a frame)
|
||||
*
|
||||
* Aside from that, you may want to enable additional debug layers to receive
|
||||
* more detailed error messages, based on your GPU backend:
|
||||
*
|
||||
* * For D3D12, the debug layer is an optional feature that can be installed
|
||||
* via "Windows Settings -> System -> Optional features" and adding the
|
||||
* "Graphics Tools" optional feature.
|
||||
* * For Vulkan, you will need to install Vulkan SDK on Windows, and on Linux,
|
||||
* you usually have some sort of `vulkan-validation-layers` system package
|
||||
* that should be installed.
|
||||
* * For Metal, it should be enough just to run the application from XCode to
|
||||
* receive detailed errors or warnings in the output.
|
||||
*
|
||||
* Don't hesitate to use tools as RenderDoc when encountering runtime issues
|
||||
* or unexpected output on screen, quick GPU frame inspection can usually help
|
||||
* you fix the majority of such problems.
|
||||
*/
|
||||
|
||||
#ifndef SDL_gpu_h_
|
||||
|
|
@ -1656,6 +1691,9 @@ typedef struct SDL_GPUStencilOpState
|
|||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GPUColorTargetDescription
|
||||
* \sa SDL_GPUBlendFactor
|
||||
* \sa SDL_GPUBlendOp
|
||||
* \sa SDL_GPUColorComponentFlags
|
||||
*/
|
||||
typedef struct SDL_GPUColorTargetBlendState
|
||||
{
|
||||
|
|
@ -2216,6 +2254,25 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
|
|||
* - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING`: the prefix to
|
||||
* use for all vertex semantics, default is "TEXCOORD".
|
||||
*
|
||||
* With the Vulkan renderer:
|
||||
*
|
||||
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN`: Enable
|
||||
* device feature shaderClipDistance. If disabled, clip distances are not
|
||||
* supported in shader code: gl_ClipDistance[] built-ins of GLSL,
|
||||
* SV_ClipDistance0/1 semantics of HLSL and [[clip_distance]] attribute of
|
||||
* Metal. Defaults to true.
|
||||
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN`: Enable device
|
||||
* feature depthClamp. If disabled, there is no depth clamp support and
|
||||
* enable_depth_clip in SDL_GPURasterizerState must always be set to true.
|
||||
* Defaults to true.
|
||||
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN`: Enable
|
||||
* device feature drawIndirectFirstInstance. If disabled, the argument
|
||||
* first_instance of SDL_GPUIndirectDrawCommand must be set to zero.
|
||||
* Defaults to true.
|
||||
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN`: Enable
|
||||
* device feature samplerAnisotropy. If disabled, enable_anisotropy of
|
||||
* SDL_GPUSamplerCreateInfo must be set to false. Defaults to true.
|
||||
*
|
||||
* \param props the properties to use.
|
||||
* \returns a GPU context on success or NULL on failure; call SDL_GetError()
|
||||
* for more information.
|
||||
|
|
@ -2230,17 +2287,21 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
|
|||
extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties(
|
||||
SDL_PropertiesID props);
|
||||
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN "SDL.gpu.device.create.vulkan.shaderclipdistance"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN "SDL.gpu.device.create.vulkan.depthclamp"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN "SDL.gpu.device.create.vulkan.drawindirectfirstinstance"
|
||||
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN "SDL.gpu.device.create.vulkan.sampleranisotropy"
|
||||
|
||||
/**
|
||||
* Destroys a GPU context previously returned by SDL_CreateGPUDevice.
|
||||
|
|
@ -2986,6 +3047,9 @@ extern SDL_DECLSPEC SDL_GPUCommandBuffer * SDLCALL SDL_AcquireGPUCommandBuffer(
|
|||
* terms this means you must ensure that vec3 and vec4 fields are 16-byte
|
||||
* aligned.
|
||||
*
|
||||
* For detailed information about accessing uniform data from a shader, please
|
||||
* refer to SDL_CreateGPUShader.
|
||||
*
|
||||
* \param command_buffer a command buffer.
|
||||
* \param slot_index the vertex uniform slot to push data to.
|
||||
* \param data client data to write.
|
||||
|
|
@ -4013,7 +4077,9 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma
|
|||
* buffer used to acquire it.
|
||||
*
|
||||
* This function will fill the swapchain texture handle with NULL if too many
|
||||
* frames are in flight. This is not an error.
|
||||
* frames are in flight. This is not an error. This NULL pointer should not be
|
||||
* passed back into SDL. Instead, it should be considered as an indication to
|
||||
* wait until the swapchain is available.
|
||||
*
|
||||
* If you use this function, it is possible to create a situation where many
|
||||
* command buffers are allocated while the rendering context waits for the GPU
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ typedef Uint32 SDL_InitFlags;
|
|||
* to run.
|
||||
*
|
||||
* See
|
||||
* [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3)
|
||||
* [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3)
|
||||
* for complete details.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
*
|
||||
* For more information, see:
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/README/main-functions
|
||||
* https://wiki.libsdl.org/SDL3/README-main-functions
|
||||
*/
|
||||
|
||||
#ifndef SDL_main_h_
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
* proper entry point for the platform, and all the other magic details
|
||||
* needed, like manually calling SDL_SetMainReady.
|
||||
*
|
||||
* Please see [README/main-functions](README/main-functions), (or
|
||||
* Please see [README-main-functions](README-main-functions), (or
|
||||
* docs/README-main-functions.md in the source tree) for a more detailed
|
||||
* explanation.
|
||||
*
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
* SDL_AppQuit. The app should not provide a `main` function in this case, and
|
||||
* doing so will likely cause the build to fail.
|
||||
*
|
||||
* Please see [README/main-functions](README/main-functions), (or
|
||||
* Please see [README-main-functions](README-main-functions), (or
|
||||
* docs/README-main-functions.md in the source tree) for a more detailed
|
||||
* explanation.
|
||||
*
|
||||
|
|
@ -512,7 +512,7 @@ typedef int (SDLCALL *SDL_main_func)(int argc, char *argv[]);
|
|||
* SDL_MAIN_USE_CALLBACKS.
|
||||
*
|
||||
* Program startup is a surprisingly complex topic. Please see
|
||||
* [README/main-functions](README/main-functions), (or
|
||||
* [README-main-functions](README-main-functions), (or
|
||||
* docs/README-main-functions.md in the source tree) for a more detailed
|
||||
* explanation.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ typedef Uint32 SDL_MouseButtonFlags;
|
|||
* with proper synchronization practices when adding other side
|
||||
* effects beyond mutation of the x and y values.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.6.
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_SetRelativeMouseTransform
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -195,6 +195,12 @@ typedef enum SDL_ProcessIO
|
|||
* run in the background. In this case the default input and output is
|
||||
* `SDL_PROCESS_STDIO_NULL` and the exitcode of the process is not
|
||||
* available, and will always be 0.
|
||||
* - `SDL_PROP_PROCESS_CREATE_CMDLINE_STRING`: a string containing the program
|
||||
* to run and any parameters. This string is passed directly to
|
||||
* `CreateProcess` on Windows, and does nothing on other platforms. This
|
||||
* property is only important if you want to start programs that does
|
||||
* non-standard command-line processing, and in most cases using
|
||||
* `SDL_PROP_PROCESS_CREATE_ARGS_POINTER` is sufficient.
|
||||
*
|
||||
* On POSIX platforms, wait() and waitpid(-1, ...) should not be called, and
|
||||
* SIGCHLD should not be ignored or handled because those would prevent SDL
|
||||
|
|
@ -231,6 +237,7 @@ extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_Pr
|
|||
#define SDL_PROP_PROCESS_CREATE_STDERR_POINTER "SDL.process.create.stderr_source"
|
||||
#define SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN "SDL.process.create.stderr_to_stdout"
|
||||
#define SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN "SDL.process.create.background"
|
||||
#define SDL_PROP_PROCESS_CREATE_CMDLINE_STRING "SDL.process.create.cmdline"
|
||||
|
||||
/**
|
||||
* Get the properties associated with a process.
|
||||
|
|
|
|||
|
|
@ -247,14 +247,14 @@ typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata);
|
|||
*
|
||||
* For more information see:
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/README/ios
|
||||
* https://wiki.libsdl.org/SDL3/README-ios
|
||||
*
|
||||
* Note that if you use the "main callbacks" instead of a standard C `main`
|
||||
* function, you don't have to use this API, as SDL will manage this for you.
|
||||
*
|
||||
* Details on main callbacks are here:
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/README/main-functions
|
||||
* https://wiki.libsdl.org/SDL3/README-main-functions
|
||||
*
|
||||
* \param window the window for which the animation callback should be set.
|
||||
* \param interval the number of frames after which **callback** will be
|
||||
|
|
|
|||
|
|
@ -1303,7 +1303,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
|||
* - `SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN` - true if
|
||||
* the application wants to use the Wayland surface for a custom role and
|
||||
* does not want it attached to an XDG toplevel window. See
|
||||
* [README/wayland](README/wayland) for more information on using custom
|
||||
* [README-wayland](README-wayland) for more information on using custom
|
||||
* surfaces.
|
||||
* - `SDL_PROP_WINDOW_CREATE_WAYLAND_CREATE_EGL_WINDOW_BOOLEAN` - true if the
|
||||
* application wants an associated `wl_egl_window` object to be created and
|
||||
|
|
@ -1311,7 +1311,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
|||
* property or `SDL_WINDOW_OPENGL` flag set.
|
||||
* - `SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER` - the wl_surface
|
||||
* associated with the window, if you want to wrap an existing window. See
|
||||
* [README/wayland](README/wayland) for more information.
|
||||
* [README-wayland](README-wayland) for more information.
|
||||
*
|
||||
* These are additional supported properties on Windows:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
|
|
@ -1485,6 +1491,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.
|
||||
}
|
||||
}
|
||||
|
|
@ -1523,8 +1530,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");
|
||||
|
|
@ -1534,10 +1543,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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -741,7 +741,7 @@ static bool MEDIAFOUNDATION_OpenDevice(SDL_Camera *device, const SDL_CameraSpec
|
|||
SDL_Log("CAMERA: opening device with symlink of '%s'", utf8symlink);
|
||||
#endif
|
||||
|
||||
wstrsymlink = WIN_UTF8ToString(utf8symlink);
|
||||
wstrsymlink = WIN_UTF8ToStringW(utf8symlink);
|
||||
if (!wstrsymlink) {
|
||||
goto failed;
|
||||
}
|
||||
|
|
@ -901,7 +901,7 @@ static char *QueryActivationObjectString(IMFActivate *activation, const GUID *pg
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char *utf8str = WIN_StringToUTF8(wstr);
|
||||
char *utf8str = WIN_StringToUTF8W(wstr);
|
||||
CoTaskMemFree(wstr);
|
||||
return utf8str;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ static bool LoadDBUSSyms(void)
|
|||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *, const char *), message_is_signal);
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, const char *), message_has_path);
|
||||
SDL_DBUS_SYM(DBusMessage *(*)(const char *, const char *, const char *, const char *), message_new_method_call);
|
||||
SDL_DBUS_SYM(DBusMessage *(*)(const char *, const char *, const char *), message_new_signal);
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, ...), message_append_args);
|
||||
SDL_DBUS_SYM(dbus_bool_t (*)(DBusMessage *, int, va_list), message_append_args_valist);
|
||||
SDL_DBUS_SYM(void (*)(DBusMessage *, DBusMessageIter *), message_iter_init_append);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ typedef struct SDL_DBusContext
|
|||
dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *);
|
||||
dbus_bool_t (*message_has_path)(DBusMessage *, const char *);
|
||||
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
|
||||
DBusMessage *(*message_new_signal)(const char *, const char *, const char *);
|
||||
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
|
||||
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
|
||||
void (*message_iter_init_append)(DBusMessage *, DBusMessageIter *);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_progressbar.h"
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_dbus.h"
|
||||
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../unix/SDL_appid.h"
|
||||
|
||||
#define UnityLauncherAPI_DBUS_INTERFACE "com.canonical.Unity.LauncherEntry"
|
||||
#define UnityLauncherAPI_DBUS_SIGNAL "Update"
|
||||
|
||||
static char *GetDBUSObjectPath()
|
||||
{
|
||||
char *app_id = SDL_strdup(SDL_GetAppID());
|
||||
|
||||
if (!app_id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Sanitize exe_name to make it a legal D-Bus path element
|
||||
for (char *p = app_id; *p; ++p) {
|
||||
if (!SDL_isalnum(*p)) {
|
||||
*p = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure it starts with a letter or underscore
|
||||
if (!SDL_isalpha(app_id[0]) && app_id[0] != '_') {
|
||||
SDL_memmove(app_id + 1, app_id, SDL_strlen(app_id) + 1);
|
||||
app_id[0] = '_';
|
||||
}
|
||||
|
||||
// Create full path
|
||||
char path[1024];
|
||||
SDL_snprintf(path, sizeof(path), "/org/libsdl/%s_%d", app_id, getpid());
|
||||
|
||||
SDL_free(app_id);
|
||||
|
||||
return SDL_strdup(path);
|
||||
}
|
||||
|
||||
static char *GetAppDesktopPath()
|
||||
{
|
||||
const char *desktop_suffix = ".desktop";
|
||||
const char *app_id = SDL_GetAppID();
|
||||
const size_t desktop_path_total_length = SDL_strlen(app_id) + SDL_strlen(desktop_suffix) + 1;
|
||||
char *desktop_path = (char *)SDL_malloc(desktop_path_total_length);
|
||||
if (!desktop_path) {
|
||||
return NULL;
|
||||
}
|
||||
*desktop_path = '\0';
|
||||
SDL_strlcat(desktop_path, app_id, desktop_path_total_length);
|
||||
SDL_strlcat(desktop_path, desktop_suffix, desktop_path_total_length);
|
||||
|
||||
return desktop_path;
|
||||
}
|
||||
|
||||
static int ShouldShowProgress(SDL_ProgressState progressState)
|
||||
{
|
||||
if (progressState == SDL_PROGRESS_STATE_INVALID ||
|
||||
progressState == SDL_PROGRESS_STATE_NONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unity LauncherAPI only supports "normal" display of progress
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
// Signal signature:
|
||||
// signal com.canonical.Unity.LauncherEntry.Update (in s app_uri, in a{sv} properties)
|
||||
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
if (!dbus || !dbus->session_conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *objectPath = GetDBUSObjectPath();
|
||||
if (!objectPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessage *msg = dbus->message_new_signal(objectPath, UnityLauncherAPI_DBUS_INTERFACE, UnityLauncherAPI_DBUS_SIGNAL);
|
||||
if (!msg) {
|
||||
SDL_free(objectPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *desktop_path = GetAppDesktopPath();
|
||||
if (!desktop_path) {
|
||||
dbus->message_unref(msg);
|
||||
SDL_free(objectPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *progress_visible_str = "progress-visible";
|
||||
const char *progress_str = "progress";
|
||||
int dbus_type_boolean_str = DBUS_TYPE_BOOLEAN;
|
||||
int dbus_type_double_str = DBUS_TYPE_DOUBLE;
|
||||
|
||||
const int progress_visible = ShouldShowProgress(window->progress_state);
|
||||
double progress = (double)window->progress_value;
|
||||
|
||||
DBusMessageIter args, props;
|
||||
dbus->message_iter_init_append(msg, &args);
|
||||
dbus->message_iter_append_basic(&args, DBUS_TYPE_STRING, &desktop_path); // Setup app_uri paramter
|
||||
dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &props); // Setup properties parameter
|
||||
DBusMessageIter key_it, value_it;
|
||||
// Set progress visible property
|
||||
dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it);
|
||||
dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_visible_str); // Append progress-visible key data
|
||||
dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_boolean_str, &value_it);
|
||||
dbus->message_iter_append_basic(&value_it, DBUS_TYPE_BOOLEAN, &progress_visible); // Append progress-visible value data
|
||||
dbus->message_iter_close_container(&key_it, &value_it);
|
||||
dbus->message_iter_close_container(&props, &key_it);
|
||||
// Set progress value property
|
||||
dbus->message_iter_open_container(&props, DBUS_TYPE_DICT_ENTRY, NULL, &key_it);
|
||||
dbus->message_iter_append_basic(&key_it, DBUS_TYPE_STRING, &progress_str); // Append progress key data
|
||||
dbus->message_iter_open_container(&key_it, DBUS_TYPE_VARIANT, (const char *)&dbus_type_double_str, &value_it);
|
||||
dbus->message_iter_append_basic(&value_it, DBUS_TYPE_DOUBLE, &progress); // Append progress value data
|
||||
dbus->message_iter_close_container(&key_it, &value_it);
|
||||
dbus->message_iter_close_container(&props, &key_it);
|
||||
dbus->message_iter_close_container(&args, &props);
|
||||
|
||||
dbus->connection_send(dbus->session_conn, msg, NULL);
|
||||
|
||||
SDL_free(desktop_path);
|
||||
dbus->message_unref(msg);
|
||||
SDL_free(objectPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // SDL_USE_LIBDBUS
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_prograssbar_h_
|
||||
#define SDL_prograssbar_h_
|
||||
|
||||
#include "../../video/SDL_sysvideo.h"
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern bool DBUS_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
#endif // SDL_prograssbar_h_
|
||||
|
|
@ -261,7 +261,7 @@ char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
|||
char *result = NULL;
|
||||
|
||||
if (WIN_IsEqualGUID(guid, &nullguid)) {
|
||||
return WIN_StringToUTF8(name); // No GUID, go with what we've got.
|
||||
return WIN_StringToUTF8W(name); // No GUID, go with what we've got.
|
||||
}
|
||||
|
||||
ptr = (const unsigned char *)guid;
|
||||
|
|
@ -270,37 +270,37 @@ char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
|||
ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6],
|
||||
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
|
||||
|
||||
strw = WIN_UTF8ToString(keystr);
|
||||
strw = WIN_UTF8ToStringW(keystr);
|
||||
rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS);
|
||||
SDL_free(strw);
|
||||
if (!rc) {
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
return WIN_StringToUTF8W(name); // oh well.
|
||||
}
|
||||
|
||||
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS);
|
||||
if (!rc) {
|
||||
RegCloseKey(hkey);
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
return WIN_StringToUTF8W(name); // oh well.
|
||||
}
|
||||
|
||||
strw = (WCHAR *)SDL_malloc(len + sizeof(WCHAR));
|
||||
if (!strw) {
|
||||
RegCloseKey(hkey);
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
return WIN_StringToUTF8W(name); // oh well.
|
||||
}
|
||||
|
||||
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE)strw, &len) == ERROR_SUCCESS);
|
||||
RegCloseKey(hkey);
|
||||
if (!rc) {
|
||||
SDL_free(strw);
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
return WIN_StringToUTF8W(name); // oh well.
|
||||
}
|
||||
|
||||
strw[len / 2] = 0; // make sure it's null-terminated.
|
||||
|
||||
result = WIN_StringToUTF8(strw);
|
||||
result = WIN_StringToUTF8W(strw);
|
||||
SDL_free(strw);
|
||||
return result ? result : WIN_StringToUTF8(name);
|
||||
return result ? result : WIN_StringToUTF8W(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -251,9 +251,9 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
|
|||
SDLBRefFilter *filter = new(std::nothrow) SDLBRefFilter(filters, nfilters);
|
||||
|
||||
if (looper == NULL || messenger == NULL || filter == NULL) {
|
||||
SDL_free(looper);
|
||||
SDL_free(messenger);
|
||||
SDL_free(filter);
|
||||
delete looper;
|
||||
delete messenger;
|
||||
delete filter;
|
||||
SDL_OutOfMemory();
|
||||
callback(userdata, NULL, -1);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -895,8 +895,12 @@ static void SDL_LogEvent(const SDL_Event *event)
|
|||
(event->type == SDL_EVENT_FINGER_MOTION) ||
|
||||
(event->type == SDL_EVENT_PEN_AXIS) ||
|
||||
(event->type == SDL_EVENT_PEN_MOTION) ||
|
||||
(event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) ||
|
||||
(event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION) ||
|
||||
(event->type == SDL_EVENT_GAMEPAD_SENSOR_UPDATE) ||
|
||||
(event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION) ||
|
||||
(event->type == SDL_EVENT_GAMEPAD_UPDATE_COMPLETE) ||
|
||||
(event->type == SDL_EVENT_JOYSTICK_AXIS_MOTION) ||
|
||||
(event->type == SDL_EVENT_JOYSTICK_UPDATE_COMPLETE) ||
|
||||
(event->type == SDL_EVENT_SENSOR_UPDATE))) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1314,8 +1314,9 @@ static void SDL_MaybeEnableWarpEmulation(SDL_Window *window, float x, float y)
|
|||
// Require two consecutive warps to the center within a certain timespan to enter warp emulation mode.
|
||||
const Uint64 now = SDL_GetTicksNS();
|
||||
if (now - mouse->last_center_warp_time_ns < WARP_EMULATION_THRESHOLD_NS) {
|
||||
if (SDL_SetRelativeMouseMode(true)) {
|
||||
mouse->warp_emulation_active = true;
|
||||
mouse->warp_emulation_active = true;
|
||||
if (!SDL_SetRelativeMouseMode(true)) {
|
||||
mouse->warp_emulation_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ char *SDL_SYS_GetPrefPath(const char *org, const char *app)
|
|||
char *SDL_SYS_GetUserFolder(SDL_Folder folder)
|
||||
{
|
||||
typedef HRESULT (WINAPI *pfnSHGetKnownFolderPath)(REFGUID /* REFKNOWNFOLDERID */, DWORD, HANDLE, PWSTR*);
|
||||
HMODULE lib = LoadLibrary(L"Shell32.dll");
|
||||
HMODULE lib = LoadLibraryW(L"Shell32.dll");
|
||||
pfnSHGetKnownFolderPath pSHGetKnownFolderPath = NULL;
|
||||
char *result = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -186,6 +186,114 @@
|
|||
#define COPYPASS_DEVICE \
|
||||
((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device
|
||||
|
||||
static bool TextureFormatIsComputeWritable[] = {
|
||||
false, // INVALID
|
||||
false, // A8_UNORM
|
||||
true, // R8_UNORM
|
||||
true, // R8G8_UNORM
|
||||
true, // R8G8B8A8_UNORM
|
||||
true, // R16_UNORM
|
||||
true, // R16G16_UNORM
|
||||
true, // R16G16B16A16_UNORM
|
||||
false, // R10G10B10A2_UNORM
|
||||
false, // B5G6R5_UNORM
|
||||
false, // B5G5R5A1_UNORM
|
||||
false, // B4G4R4A4_UNORM
|
||||
false, // B8G8R8A8_UNORM
|
||||
false, // BC1_UNORM
|
||||
false, // BC2_UNORM
|
||||
false, // BC3_UNORM
|
||||
false, // BC4_UNORM
|
||||
false, // BC5_UNORM
|
||||
false, // BC7_UNORM
|
||||
false, // BC6H_FLOAT
|
||||
false, // BC6H_UFLOAT
|
||||
true, // R8_SNORM
|
||||
true, // R8G8_SNORM
|
||||
true, // R8G8B8A8_SNORM
|
||||
true, // R16_SNORM
|
||||
true, // R16G16_SNORM
|
||||
true, // R16G16B16A16_SNORM
|
||||
true, // R16_FLOAT
|
||||
true, // R16G16_FLOAT
|
||||
true, // R16G16B16A16_FLOAT
|
||||
true, // R32_FLOAT
|
||||
true, // R32G32_FLOAT
|
||||
true, // R32G32B32A32_FLOAT
|
||||
false, // R11G11B10_UFLOAT
|
||||
true, // R8_UINT
|
||||
true, // R8G8_UINT
|
||||
true, // R8G8B8A8_UINT
|
||||
true, // R16_UINT
|
||||
true, // R16G16_UINT
|
||||
true, // R16G16B16A16_UINT
|
||||
true, // R32_UINT
|
||||
true, // R32G32_UINT
|
||||
true, // R32G32B32A32_UINT
|
||||
true, // R8_INT
|
||||
true, // R8G8_INT
|
||||
true, // R8G8B8A8_INT
|
||||
true, // R16_INT
|
||||
true, // R16G16_INT
|
||||
true, // R16G16B16A16_INT
|
||||
true, // R32_INT
|
||||
true, // R32G32_INT
|
||||
true, // R32G32B32A32_INT
|
||||
false, // R8G8B8A8_UNORM_SRGB
|
||||
false, // B8G8R8A8_UNORM_SRGB
|
||||
false, // BC1_UNORM_SRGB
|
||||
false, // BC3_UNORM_SRGB
|
||||
false, // BC3_UNORM_SRGB
|
||||
false, // BC7_UNORM_SRGB
|
||||
false, // D16_UNORM
|
||||
false, // D24_UNORM
|
||||
false, // D32_FLOAT
|
||||
false, // D24_UNORM_S8_UINT
|
||||
false, // D32_FLOAT_S8_UINT
|
||||
false, // ASTC_4x4_UNORM
|
||||
false, // ASTC_5x4_UNORM
|
||||
false, // ASTC_5x5_UNORM
|
||||
false, // ASTC_6x5_UNORM
|
||||
false, // ASTC_6x6_UNORM
|
||||
false, // ASTC_8x5_UNORM
|
||||
false, // ASTC_8x6_UNORM
|
||||
false, // ASTC_8x8_UNORM
|
||||
false, // ASTC_10x5_UNORM
|
||||
false, // ASTC_10x6_UNORM
|
||||
false, // ASTC_10x8_UNORM
|
||||
false, // ASTC_10x10_UNORM
|
||||
false, // ASTC_12x10_UNORM
|
||||
false, // ASTC_12x12_UNORM
|
||||
false, // ASTC_4x4_UNORM_SRGB
|
||||
false, // ASTC_5x4_UNORM_SRGB
|
||||
false, // ASTC_5x5_UNORM_SRGB
|
||||
false, // ASTC_6x5_UNORM_SRGB
|
||||
false, // ASTC_6x6_UNORM_SRGB
|
||||
false, // ASTC_8x5_UNORM_SRGB
|
||||
false, // ASTC_8x6_UNORM_SRGB
|
||||
false, // ASTC_8x8_UNORM_SRGB
|
||||
false, // ASTC_10x5_UNORM_SRGB
|
||||
false, // ASTC_10x6_UNORM_SRGB
|
||||
false, // ASTC_10x8_UNORM_SRGB
|
||||
false, // ASTC_10x10_UNORM_SRGB
|
||||
false, // ASTC_12x10_UNORM_SRGB
|
||||
false, // ASTC_12x12_UNORM_SRGB
|
||||
false, // ASTC_4x4_FLOAT
|
||||
false, // ASTC_5x4_FLOAT
|
||||
false, // ASTC_5x5_FLOAT
|
||||
false, // ASTC_6x5_FLOAT
|
||||
false, // ASTC_6x6_FLOAT
|
||||
false, // ASTC_8x5_FLOAT
|
||||
false, // ASTC_8x6_FLOAT
|
||||
false, // ASTC_8x8_FLOAT
|
||||
false, // ASTC_10x5_FLOAT
|
||||
false, // ASTC_10x6_FLOAT
|
||||
false, // ASTC_10x8_FLOAT
|
||||
false, // ASTC_10x10_FLOAT
|
||||
false, // ASTC_12x10_FLOAT
|
||||
false // ASTC_12x12_FLOAT
|
||||
};
|
||||
|
||||
// Drivers
|
||||
|
||||
#ifndef SDL_GPU_DISABLED
|
||||
|
|
@ -450,7 +558,7 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
|
|||
SDL_SetError("Required shader format for backend %s not provided!", gpudriver);
|
||||
return NULL;
|
||||
}
|
||||
if (backends[i]->PrepareDriver(_this)) {
|
||||
if (backends[i]->PrepareDriver(_this, props)) {
|
||||
return backends[i];
|
||||
}
|
||||
}
|
||||
|
|
@ -465,7 +573,7 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
|
|||
// Don't select a backend which doesn't support the app's shaders.
|
||||
continue;
|
||||
}
|
||||
if (backends[i]->PrepareDriver(_this)) {
|
||||
if (backends[i]->PrepareDriver(_this, props)) {
|
||||
return backends[i];
|
||||
}
|
||||
}
|
||||
|
|
@ -760,6 +868,13 @@ bool SDL_GPUTextureSupportsFormat(
|
|||
CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false)
|
||||
}
|
||||
|
||||
if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
|
||||
(usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
|
||||
if (!TextureFormatIsComputeWritable[format]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return device->SupportsTextureFormat(
|
||||
device->driverData,
|
||||
format,
|
||||
|
|
@ -1522,30 +1637,47 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
|
||||
if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
|
||||
SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
if (color_target_infos[i].resolve_texture == NULL) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
|
||||
return NULL;
|
||||
} else {
|
||||
TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
|
||||
if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
|
||||
SDL_assert_release(!"Resolve texture must have a sample count of 1!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.format != textureHeader->info.format) {
|
||||
SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
|
||||
return NULL;
|
||||
}
|
||||
if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
|
||||
SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
|
||||
return NULL;
|
||||
}
|
||||
if (!(resolveTextureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
|
||||
SDL_assert_release(!"Resolve texture usage must include COLOR_TARGET!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (color_target_infos[i].layer_or_depth_plane >= textureHeader->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Color target layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_target_infos[i].mip_level >= textureHeader->info.num_levels) {
|
||||
SDL_assert_release(!"Color target mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info != NULL) {
|
||||
|
|
@ -1553,10 +1685,12 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
|
||||
if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
|
||||
SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
|
||||
SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
|
||||
|
|
@ -1564,6 +1698,7 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
|
|||
depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
|
||||
depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
|
||||
SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1756,7 +1891,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(
|
||||
|
|
@ -1836,7 +1975,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(
|
||||
|
|
@ -2074,6 +2217,16 @@ SDL_GPUComputePass *SDL_BeginGPUComputePass(
|
|||
SDL_assert_release(!"Texture must be created with COMPUTE_STORAGE_WRITE or COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE flag");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].layer >= header->info.layer_count_or_depth) {
|
||||
SDL_assert_release(!"Storage texture layer index must be less than the texture's layer count!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (storage_texture_bindings[i].mip_level >= header->info.num_levels) {
|
||||
SDL_assert_release(!"Storage texture mip level must be less than the texture's level count!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: validate buffer usage?
|
||||
|
|
@ -2605,11 +2758,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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1140,7 +1142,7 @@ typedef struct SDL_GPUBootstrap
|
|||
{
|
||||
const char *name;
|
||||
const SDL_GPUShaderFormat shader_formats;
|
||||
bool (*PrepareDriver)(SDL_VideoDevice *_this);
|
||||
bool (*PrepareDriver)(SDL_VideoDevice *_this, SDL_PropertiesID props);
|
||||
SDL_GPUDevice *(*CreateDevice)(bool debug_mode, bool prefer_low_power, SDL_PropertiesID props);
|
||||
} SDL_GPUBootstrap;
|
||||
|
||||
|
|
|
|||
|
|
@ -8317,7 +8317,7 @@ static void D3D12_INTERNAL_InitBlitResources(
|
|||
}
|
||||
}
|
||||
|
||||
static bool D3D12_PrepareDriver(SDL_VideoDevice *_this)
|
||||
static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
|
||||
{
|
||||
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -4307,7 +4307,7 @@ static bool METAL_SupportsTextureFormat(
|
|||
|
||||
// Device Creation
|
||||
|
||||
static bool METAL_PrepareDriver(SDL_VideoDevice *this)
|
||||
static bool METAL_PrepareDriver(SDL_VideoDevice *this, SDL_PropertiesID props)
|
||||
{
|
||||
if (@available(macOS 10.14, iOS 13.0, tvOS 13.0, *)) {
|
||||
return (this->Metal_CreateView != NULL);
|
||||
|
|
|
|||
|
|
@ -703,7 +703,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;
|
||||
|
|
@ -1088,6 +1088,7 @@ struct VulkanRenderer
|
|||
VkPhysicalDevice physicalDevice;
|
||||
VkPhysicalDeviceProperties2KHR physicalDeviceProperties;
|
||||
VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties;
|
||||
VkPhysicalDeviceFeatures desiredDeviceFeatures;
|
||||
VkDevice logicalDevice;
|
||||
Uint8 integratedMemoryNotification;
|
||||
Uint8 outOfDeviceLocalMemoryWarning;
|
||||
|
|
@ -3164,7 +3165,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;
|
||||
|
|
@ -3193,7 +3193,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,
|
||||
|
|
@ -3202,6 +3203,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(
|
||||
|
|
@ -4779,6 +4784,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,
|
||||
|
|
@ -4798,8 +4809,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;
|
||||
|
|
@ -8149,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;
|
||||
|
||||
|
|
@ -10020,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;
|
||||
|
|
@ -10561,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;
|
||||
|
|
@ -11212,12 +11221,14 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
|
|||
renderer->vkGetPhysicalDeviceFeatures(
|
||||
physicalDevice,
|
||||
&deviceFeatures);
|
||||
if (!deviceFeatures.independentBlend ||
|
||||
!deviceFeatures.imageCubeArray ||
|
||||
!deviceFeatures.depthClamp ||
|
||||
!deviceFeatures.shaderClipDistance ||
|
||||
!deviceFeatures.drawIndirectFirstInstance ||
|
||||
!deviceFeatures.sampleRateShading) {
|
||||
|
||||
if ((!deviceFeatures.independentBlend && renderer->desiredDeviceFeatures.independentBlend) ||
|
||||
(!deviceFeatures.imageCubeArray && renderer->desiredDeviceFeatures.imageCubeArray) ||
|
||||
(!deviceFeatures.depthClamp && renderer->desiredDeviceFeatures.depthClamp) ||
|
||||
(!deviceFeatures.shaderClipDistance && renderer->desiredDeviceFeatures.shaderClipDistance) ||
|
||||
(!deviceFeatures.drawIndirectFirstInstance && renderer->desiredDeviceFeatures.drawIndirectFirstInstance) ||
|
||||
(!deviceFeatures.sampleRateShading && renderer->desiredDeviceFeatures.sampleRateShading) ||
|
||||
(!deviceFeatures.samplerAnisotropy && renderer->desiredDeviceFeatures.samplerAnisotropy)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -11433,7 +11444,6 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
|
|||
{
|
||||
VkResult vulkanResult;
|
||||
VkDeviceCreateInfo deviceCreateInfo;
|
||||
VkPhysicalDeviceFeatures desiredDeviceFeatures;
|
||||
VkPhysicalDeviceFeatures haveDeviceFeatures;
|
||||
VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
|
||||
const char **deviceExtensions;
|
||||
|
|
@ -11457,22 +11467,13 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
|
|||
|
||||
// specifying used device features
|
||||
|
||||
SDL_zero(desiredDeviceFeatures);
|
||||
desiredDeviceFeatures.independentBlend = VK_TRUE;
|
||||
desiredDeviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
desiredDeviceFeatures.imageCubeArray = VK_TRUE;
|
||||
desiredDeviceFeatures.depthClamp = VK_TRUE;
|
||||
desiredDeviceFeatures.shaderClipDistance = VK_TRUE;
|
||||
desiredDeviceFeatures.drawIndirectFirstInstance = VK_TRUE;
|
||||
desiredDeviceFeatures.sampleRateShading = VK_TRUE;
|
||||
|
||||
if (haveDeviceFeatures.fillModeNonSolid) {
|
||||
desiredDeviceFeatures.fillModeNonSolid = VK_TRUE;
|
||||
renderer->desiredDeviceFeatures.fillModeNonSolid = VK_TRUE;
|
||||
renderer->supportsFillModeNonSolid = true;
|
||||
}
|
||||
|
||||
if (haveDeviceFeatures.multiDrawIndirect) {
|
||||
desiredDeviceFeatures.multiDrawIndirect = VK_TRUE;
|
||||
renderer->desiredDeviceFeatures.multiDrawIndirect = VK_TRUE;
|
||||
renderer->supportsMultiDrawIndirect = true;
|
||||
}
|
||||
|
||||
|
|
@ -11513,7 +11514,7 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
|
|||
deviceCreateInfo.enabledExtensionCount);
|
||||
CreateDeviceExtensionArray(&renderer->supports, deviceExtensions);
|
||||
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions;
|
||||
deviceCreateInfo.pEnabledFeatures = &desiredDeviceFeatures;
|
||||
deviceCreateInfo.pEnabledFeatures = &renderer->desiredDeviceFeatures;
|
||||
|
||||
vulkanResult = renderer->vkCreateDevice(
|
||||
renderer->physicalDevice,
|
||||
|
|
@ -11598,11 +11599,11 @@ static bool VULKAN_INTERNAL_PrepareVulkan(
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
|
||||
static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
|
||||
{
|
||||
// Set up dummy VulkanRenderer
|
||||
VulkanRenderer *renderer;
|
||||
Uint8 result;
|
||||
bool result = false;
|
||||
|
||||
if (_this->Vulkan_CreateSurface == NULL) {
|
||||
return false;
|
||||
|
|
@ -11612,16 +11613,27 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
|
|||
return false;
|
||||
}
|
||||
|
||||
renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
|
||||
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
|
||||
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
|
||||
if (renderer) {
|
||||
// Opt out device features (higher compatibility in exchange for reduced functionality)
|
||||
renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
|
||||
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
|
||||
// These features have near universal support so they are always enabled
|
||||
renderer->desiredDeviceFeatures.independentBlend = VK_TRUE;
|
||||
renderer->desiredDeviceFeatures.sampleRateShading = VK_TRUE;
|
||||
renderer->desiredDeviceFeatures.imageCubeArray = VK_TRUE;
|
||||
|
||||
if (result) {
|
||||
renderer->vkDestroyInstance(renderer->instance, NULL);
|
||||
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
|
||||
if (result) {
|
||||
renderer->vkDestroyInstance(renderer->instance, NULL);
|
||||
}
|
||||
SDL_free(renderer);
|
||||
}
|
||||
SDL_free(renderer);
|
||||
SDL_Vulkan_UnloadLibrary();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -11642,12 +11654,27 @@ 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;
|
||||
|
||||
// Opt out device features (higher compatibility in exchange for reduced functionality)
|
||||
renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
|
||||
|
||||
// These features have near universal support so they are always enabled
|
||||
renderer->desiredDeviceFeatures.independentBlend = VK_TRUE;
|
||||
renderer->desiredDeviceFeatures.sampleRateShading = VK_TRUE;
|
||||
renderer->desiredDeviceFeatures.imageCubeArray = VK_TRUE;
|
||||
|
||||
if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
|
||||
SDL_free(renderer);
|
||||
SDL_Vulkan_UnloadLibrary();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -779,6 +779,22 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||
}
|
||||
break;
|
||||
}
|
||||
} else if (vendor == USB_VENDOR_8BITDO &&
|
||||
(product == USB_PRODUCT_8BITDO_SF30_PRO ||
|
||||
product == USB_PRODUCT_8BITDO_SF30_PRO_BT ||
|
||||
product == USB_PRODUCT_8BITDO_SN30_PRO ||
|
||||
product == USB_PRODUCT_8BITDO_SN30_PRO_BT ||
|
||||
product == USB_PRODUCT_8BITDO_PRO_2 ||
|
||||
product == USB_PRODUCT_8BITDO_PRO_2_BT)) {
|
||||
SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||
if (product == USB_PRODUCT_8BITDO_PRO_2 || product == USB_PRODUCT_8BITDO_PRO_2_BT) {
|
||||
SDL_strlcat(mapping_string, "paddle1:b14,paddle2:b13,", sizeof(mapping_string));
|
||||
}
|
||||
} else if (vendor == USB_VENDOR_8BITDO &&
|
||||
(product == USB_PRODUCT_8BITDO_SF30_PRO ||
|
||||
product == USB_PRODUCT_8BITDO_SF30_PRO_BT)) {
|
||||
// This controller has no guide button
|
||||
SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||
} else {
|
||||
// All other gamepads have the standard set of 19 buttons and 6 axes
|
||||
if (SDL_IsJoystickGameCube(vendor, product)) {
|
||||
|
|
@ -802,20 +818,20 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
|||
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickGoogleStadiaController(vendor, product)) {
|
||||
// The Google Stadia controller has a share button and a Google Assistant button
|
||||
SDL_strlcat(mapping_string, "misc1:b11,misc2:b12", sizeof(mapping_string));
|
||||
SDL_strlcat(mapping_string, "misc1:b11,misc2:b12,", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystickNVIDIASHIELDController(vendor, product)) {
|
||||
// The NVIDIA SHIELD controller has a share button between back and start buttons
|
||||
SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
|
||||
|
||||
if (product == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
|
||||
// The original SHIELD controller has a touchpad and plus/minus buttons as well
|
||||
SDL_strlcat(mapping_string, "touchpad:b12,misc2:b13,misc3:b14", sizeof(mapping_string));
|
||||
SDL_strlcat(mapping_string, "touchpad:b12,misc2:b13,misc3:b14,", sizeof(mapping_string));
|
||||
}
|
||||
} else if (SDL_IsJoystickHoriSteamController(vendor, product)) {
|
||||
/* The Wireless HORIPad for Steam has QAM, Steam, Capsense L/R Sticks, 2 rear buttons, and 2 misc buttons */
|
||||
SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17", sizeof(mapping_string));
|
||||
} else if (SDL_IsJoystick8BitDoController(vendor, product)) {
|
||||
SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,paddle3:b14,paddle4:b13", sizeof(mapping_string));
|
||||
SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17,", sizeof(mapping_string));
|
||||
} else if (vendor == USB_VENDOR_8BITDO && product == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
||||
SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,paddle3:b14,paddle4:b13,", sizeof(mapping_string));
|
||||
} else {
|
||||
switch (SDL_GetGamepadTypeFromGUID(guid, NULL)) {
|
||||
case SDL_GAMEPAD_TYPE_PS4:
|
||||
|
|
@ -1295,7 +1311,7 @@ static bool SDL_PrivateParseGamepadElement(SDL_Gamepad *gamepad, const char *szG
|
|||
static bool SDL_PrivateParseGamepadConfigString(SDL_Gamepad *gamepad, const char *pchString)
|
||||
{
|
||||
char szGameButton[20];
|
||||
char szJoystickButton[20];
|
||||
char szJoystickButton[128];
|
||||
bool bGameButton = true;
|
||||
int i = 0;
|
||||
const char *pchPos = pchString;
|
||||
|
|
|
|||
|
|
@ -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[] = {
|
|||
"03000000790000004418000000010000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,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,",
|
||||
|
|
|
|||
|
|
@ -3175,11 +3175,6 @@ bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id)
|
|||
return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT);
|
||||
}
|
||||
|
||||
bool SDL_IsJoystick8BitDoController(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return vendor_id == USB_VENDOR_8BITDO && (product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS);
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
EControllerType eType = GuessControllerType(vendor_id, product_id);
|
||||
|
|
|
|||
|
|
@ -135,9 +135,6 @@ extern bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
|
|||
// Function to return whether a joystick is a HORI Steam controller
|
||||
extern bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick is a 8BitDo controller
|
||||
extern bool SDL_IsJoystick8BitDoController(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick is a Steam Deck
|
||||
extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -346,7 +346,9 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|||
(device->is_switch_joycon_pair && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR, 0, "")) ||
|
||||
(device->is_stadia && HIDAPI_IsDevicePresent(USB_VENDOR_GOOGLE, USB_PRODUCT_GOOGLE_STADIA_CONTROLLER, 0, "")) ||
|
||||
(device->is_switch_joyconL && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT, 0, "")) ||
|
||||
(device->is_switch_joyconR && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT, 0, ""))) {
|
||||
(device->is_switch_joyconR && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT, 0, "")) ||
|
||||
(SDL_strcmp(name, "8Bitdo SN30 Pro") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO_BT, 0, ""))) ||
|
||||
(SDL_strcmp(name, "8BitDo Pro 2") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2_BT, 0, "")))) {
|
||||
// The HIDAPI driver is taking care of this device
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ enum
|
|||
SDL_GAMEPAD_NUM_8BITDO_BUTTONS,
|
||||
};
|
||||
|
||||
#define SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID 0x06
|
||||
#define SDL_8BITDO_REPORTID_SDL_REPORTID 0x04
|
||||
#define SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID 0x03
|
||||
#define SDL_8BITDO_BT_REPORTID_SDL_REPORTID 0x01
|
||||
|
||||
#define ABITDO_ACCEL_SCALE 4096.f
|
||||
#define SENSOR_INTERVAL_NS 8000000ULL
|
||||
|
||||
|
|
@ -112,9 +117,30 @@ static bool HIDAPI_Driver8BitDo_IsEnabled(void)
|
|||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
|
||||
}
|
||||
|
||||
static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
|
||||
{
|
||||
SDL_memset(report, 0, length);
|
||||
report[0] = report_id;
|
||||
return SDL_hid_get_feature_report(dev, report, length);
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
|
||||
{
|
||||
return SDL_IsJoystick8BitDoController(vendor_id, product_id);
|
||||
if (vendor_id == USB_VENDOR_8BITDO) {
|
||||
switch (product_id) {
|
||||
case USB_PRODUCT_8BITDO_SF30_PRO:
|
||||
case USB_PRODUCT_8BITDO_SF30_PRO_BT:
|
||||
case USB_PRODUCT_8BITDO_SN30_PRO:
|
||||
case USB_PRODUCT_8BITDO_SN30_PRO_BT:
|
||||
case USB_PRODUCT_8BITDO_PRO_2:
|
||||
case USB_PRODUCT_8BITDO_PRO_2_BT:
|
||||
case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
|
||||
|
|
@ -128,15 +154,40 @@ static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
|
|||
if (device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
||||
// The Ultimate 2 Wireless v1.02 firmware has 12 byte reports, v1.03 firmware has 34 byte reports
|
||||
const int ULTIMATE2_WIRELESS_V103_REPORT_SIZE = 34;
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
|
||||
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 80);
|
||||
if (size == 0) {
|
||||
// Try again
|
||||
continue;
|
||||
}
|
||||
if (size >= ULTIMATE2_WIRELESS_V103_REPORT_SIZE) {
|
||||
ctx->sensors_supported = true;
|
||||
ctx->rumble_supported = true;
|
||||
ctx->powerstate_supported = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 80);
|
||||
if (size >= ULTIMATE2_WIRELESS_V103_REPORT_SIZE) {
|
||||
int size = ReadFeatureReport(device->dev, SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID, data, sizeof(data));
|
||||
if (size > 0) {
|
||||
ctx->sensors_supported = true;
|
||||
ctx->rumble_supported = true;
|
||||
ctx->powerstate_supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->product_id == USB_PRODUCT_8BITDO_SF30_PRO || device->product_id == USB_PRODUCT_8BITDO_SF30_PRO_BT) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo SF30 Pro");
|
||||
} else if (device->product_id == USB_PRODUCT_8BITDO_SN30_PRO || device->product_id == USB_PRODUCT_8BITDO_SN30_PRO_BT) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo SN30 Pro");
|
||||
} else if (device->product_id == USB_PRODUCT_8BITDO_PRO_2 || device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo Pro 2");
|
||||
}
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +213,14 @@ static bool HIDAPI_Driver8BitDo_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
|
|||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
// Initialize the joystick capabilities
|
||||
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
|
||||
if (device->product_id == USB_PRODUCT_8BITDO_PRO_2 ||
|
||||
device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT ||
|
||||
device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
||||
// This controller has additional buttons
|
||||
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
|
||||
} else {
|
||||
joystick->nbuttons = 11;
|
||||
}
|
||||
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
|
||||
joystick->nhats = 1;
|
||||
|
||||
|
|
@ -232,11 +290,95 @@ static bool HIDAPI_Driver8BitDo_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *dev
|
|||
}
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_HandleOldStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->last_state[2] != data[2]) {
|
||||
Uint8 hat;
|
||||
|
||||
switch (data[2]) {
|
||||
case 0:
|
||||
hat = SDL_HAT_UP;
|
||||
break;
|
||||
case 1:
|
||||
hat = SDL_HAT_RIGHTUP;
|
||||
break;
|
||||
case 2:
|
||||
hat = SDL_HAT_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
hat = SDL_HAT_RIGHTDOWN;
|
||||
break;
|
||||
case 4:
|
||||
hat = SDL_HAT_DOWN;
|
||||
break;
|
||||
case 5:
|
||||
hat = SDL_HAT_LEFTDOWN;
|
||||
break;
|
||||
case 6:
|
||||
hat = SDL_HAT_LEFT;
|
||||
break;
|
||||
case 7:
|
||||
hat = SDL_HAT_LEFTUP;
|
||||
break;
|
||||
default:
|
||||
hat = SDL_HAT_CENTERED;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
}
|
||||
|
||||
if (ctx->last_state[0] != data[0]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x02) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x40) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x80) != 0));
|
||||
}
|
||||
|
||||
if (ctx->last_state[1] != data[1]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x04) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x20) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x40) != 0));
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[1] & 0x01) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[1] & 0x02) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
|
||||
}
|
||||
|
||||
#define READ_STICK_AXIS(offset) \
|
||||
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16))
|
||||
{
|
||||
axis = READ_STICK_AXIS(3);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = READ_STICK_AXIS(4);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
axis = READ_STICK_AXIS(5);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = READ_STICK_AXIS(6);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
}
|
||||
#undef READ_STICK_AXIS
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
if (data[0] != 0x03 && data[0] != 0x01) {
|
||||
|
||||
switch (data[0]) {
|
||||
case SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID: // Firmware without enhanced mode
|
||||
case SDL_8BITDO_REPORTID_SDL_REPORTID: // Enhanced mode USB report
|
||||
case SDL_8BITDO_BT_REPORTID_SDL_REPORTID: // Enhanced mode Bluetooth report
|
||||
break;
|
||||
default:
|
||||
// We don't know how to handle this report
|
||||
return;
|
||||
}
|
||||
|
|
@ -297,7 +439,7 @@ static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
|
||||
}
|
||||
|
||||
if (ctx->last_state[10] != data[10]) {
|
||||
if (size > 10 && ctx->last_state[10] != data[10]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_L4, ((data[10] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_R4, ((data[10] & 0x02) != 0));
|
||||
}
|
||||
|
|
@ -355,7 +497,6 @@ static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
}
|
||||
|
||||
|
||||
if (ctx->sensors_enabled) {
|
||||
Uint64 sensor_timestamp;
|
||||
float values[3];
|
||||
|
|
@ -414,7 +555,12 @@ static bool HIDAPI_Driver8BitDo_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
continue;
|
||||
}
|
||||
|
||||
HIDAPI_Driver8BitDo_HandleStatePacket(joystick, ctx, data, size);
|
||||
if (size == 9) {
|
||||
// Old firmware USB report for the SF30 Pro and SN30 Pro controllers
|
||||
HIDAPI_Driver8BitDo_HandleOldStatePacket(joystick, ctx, data, size);
|
||||
} else {
|
||||
HIDAPI_Driver8BitDo_HandleStatePacket(joystick, ctx, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -60,12 +60,19 @@
|
|||
#define USB_VENDOR_ZEROPLUS 0x0c12
|
||||
|
||||
#define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS 0x6012
|
||||
#define USB_PRODUCT_8BITDO_SF30_PRO 0x6000 // B + START
|
||||
#define USB_PRODUCT_8BITDO_SF30_PRO_BT 0x6100 // B + START
|
||||
#define USB_PRODUCT_8BITDO_SN30_PRO 0x6001 // B + START
|
||||
#define USB_PRODUCT_8BITDO_SN30_PRO_BT 0x6101 // B + START
|
||||
#define USB_PRODUCT_8BITDO_PRO_2 0x6003 // mode switch to D
|
||||
#define USB_PRODUCT_8BITDO_PRO_2_BT 0x6006 // mode switch to D
|
||||
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
|
||||
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
|
||||
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103
|
||||
#define USB_PRODUCT_BACKBONE_ONE_IOS_PS5 0x0104
|
||||
#define USB_PRODUCT_BDA_XB1_CLASSIC 0x581a
|
||||
#define USB_PRODUCT_BDA_XB1_FIGHTPAD 0x791a
|
||||
#define USB_PRODUCT_BDA_XB1_SPECTRA_PRO 0x592a
|
||||
#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER 0x9400
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER1 0x1843
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2 0x1844
|
||||
|
|
@ -96,6 +103,7 @@
|
|||
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 0x7210
|
||||
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104 0x7214
|
||||
#define USB_PRODUCT_PDP_ROCK_CANDY 0x0246
|
||||
#define USB_PRODUCT_POWERA_MINI 0x541a
|
||||
#define USB_PRODUCT_RAZER_ATROX 0x0a00
|
||||
#define USB_PRODUCT_RAZER_KITSUNE 0x1012
|
||||
#define USB_PRODUCT_RAZER_PANTHERA 0x0401
|
||||
|
|
@ -124,6 +132,7 @@
|
|||
#define USB_PRODUCT_STEALTH_ULTRA_WIRED 0x7073
|
||||
#define USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER 0x0575
|
||||
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_PS4 0xd00e
|
||||
#define USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE 0xb68c
|
||||
#define USB_PRODUCT_VALVE_STEAM_CONTROLLER_DONGLE 0x1142
|
||||
#define USB_PRODUCT_VICTRIX_FS_PRO 0x0203
|
||||
#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ static bool QueryDeviceName(LPDIRECTINPUTDEVICE8 device, Uint16 vendor_id, Uint1
|
|||
}
|
||||
|
||||
*manufacturer_string = NULL;
|
||||
*product_string = WIN_StringToUTF8(dipstr.wsz);
|
||||
*product_string = WIN_StringToUTF8W(dipstr.wsz);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,18 @@ SDL_Process *SDL_CreateProcess(const char * const *args, bool pipe_stdio)
|
|||
SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props)
|
||||
{
|
||||
const char * const *args = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, NULL);
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
const char *cmdline = SDL_GetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, NULL);
|
||||
if ((!args || !args[0] || !args[0][0]) && (!cmdline || !cmdline[0])) {
|
||||
SDL_SetError("Either SDL_PROP_PROCESS_CREATE_ARGS_POINTER or SDL_PROP_PROCESS_CREATE_CMDLINE_STRING must be valid");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (!args || !args[0] || !args[0][0]) {
|
||||
SDL_InvalidParamError("SDL_PROP_PROCESS_CREATE_ARGS_POINTER");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_Process *process = (SDL_Process *)SDL_calloc(1, sizeof(*process));
|
||||
if (!process) {
|
||||
|
|
|
|||
|
|
@ -106,9 +106,12 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
|
|||
len = 0;
|
||||
for (i = 0; args[i]; i++) {
|
||||
const char *a = args[i];
|
||||
bool quotes = *a == '\0' || SDL_strpbrk(a, " \r\n\t\v") != NULL;
|
||||
|
||||
/* two double quotes to surround an argument with */
|
||||
len += 2;
|
||||
if (quotes) {
|
||||
/* surround the argument with double quote if it is empty or contains whitespaces */
|
||||
len += 2;
|
||||
}
|
||||
|
||||
for (; *a; a++) {
|
||||
switch (*a) {
|
||||
|
|
@ -116,8 +119,8 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
|
|||
len += 2;
|
||||
break;
|
||||
case '\\':
|
||||
/* only escape backslashes that precede a double quote */
|
||||
len += (a[1] == '"' || a[1] == '\0') ? 2 : 1;
|
||||
/* only escape backslashes that precede a double quote (including the enclosing double quote) */
|
||||
len += (a[1] == '"' || (quotes && a[1] == '\0')) ? 2 : 1;
|
||||
break;
|
||||
case ' ':
|
||||
case '^':
|
||||
|
|
@ -149,8 +152,11 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
|
|||
i_out = 0;
|
||||
for (i = 0; args[i]; i++) {
|
||||
const char *a = args[i];
|
||||
bool quotes = *a == '\0' || SDL_strpbrk(a, " \r\n\t\v") != NULL;
|
||||
|
||||
result[i_out++] = '"';
|
||||
if (quotes) {
|
||||
result[i_out++] = '"';
|
||||
}
|
||||
for (; *a; a++) {
|
||||
switch (*a) {
|
||||
case '"':
|
||||
|
|
@ -163,7 +169,7 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
|
|||
break;
|
||||
case '\\':
|
||||
result[i_out++] = *a;
|
||||
if (a[1] == '"' || a[1] == '\0') {
|
||||
if (a[1] == '"' || (quotes && a[1] == '\0')) {
|
||||
result[i_out++] = *a;
|
||||
}
|
||||
break;
|
||||
|
|
@ -188,7 +194,9 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
|
|||
break;
|
||||
}
|
||||
}
|
||||
result[i_out++] = '"';
|
||||
if (quotes) {
|
||||
result[i_out++] = '"';
|
||||
}
|
||||
result[i_out++] = ' ';
|
||||
}
|
||||
SDL_assert(i_out == len);
|
||||
|
|
@ -237,6 +245,7 @@ static bool join_env(char **env, LPWSTR *env_out)
|
|||
bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID props)
|
||||
{
|
||||
const char * const *args = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, NULL);
|
||||
const char *cmdline = SDL_GetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, NULL);
|
||||
SDL_Environment *env = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER, SDL_GetEnvironment());
|
||||
char **envp = NULL;
|
||||
const char *working_directory = SDL_GetStringProperty(props, SDL_PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING, NULL);
|
||||
|
|
@ -286,7 +295,12 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||
security_attributes.bInheritHandle = TRUE;
|
||||
security_attributes.lpSecurityDescriptor = NULL;
|
||||
|
||||
if (!join_arguments(args, &createprocess_cmdline)) {
|
||||
if (cmdline) {
|
||||
createprocess_cmdline = WIN_UTF8ToString(cmdline);
|
||||
if (!createprocess_cmdline) {
|
||||
goto done;
|
||||
}
|
||||
} else if (!join_arguments(args, &createprocess_cmdline)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2627,11 +2627,12 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer)
|
|||
const float logical_h = view->logical_h;
|
||||
int iwidth, iheight;
|
||||
|
||||
if (renderer->target) {
|
||||
if (is_main_view) {
|
||||
SDL_GetRenderOutputSize(renderer, &iwidth, &iheight);
|
||||
} else {
|
||||
SDL_assert(renderer->target != NULL);
|
||||
iwidth = (int)renderer->target->w;
|
||||
iheight = (int)renderer->target->h;
|
||||
} else {
|
||||
SDL_GetRenderOutputSize(renderer, &iwidth, &iheight);
|
||||
}
|
||||
|
||||
view->logical_src_rect.x = 0.0f;
|
||||
|
|
|
|||
|
|
@ -2511,13 +2511,7 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const
|
|||
/* Ctrl-G toggle mouse grab */
|
||||
SDL_Window *window = SDL_GetWindowFromEvent(event);
|
||||
if (window) {
|
||||
if (SDL_RectEmpty(SDL_GetWindowMouseRect(window))) {
|
||||
SDL_Rect r = { 10, 10, 200, 200};
|
||||
SDL_SetWindowMouseRect(window, &r);
|
||||
} else {
|
||||
SDL_SetWindowMouseRect(window, NULL);
|
||||
}
|
||||
//SDL_SetWindowMouseGrab(window, !SDL_GetWindowMouseGrab(window));
|
||||
SDL_SetWindowMouseGrab(window, !SDL_GetWindowMouseGrab(window));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2266,6 +2266,12 @@ static void SDL_FinishWindowCreation(SDL_Window *window, SDL_WindowFlags flags)
|
|||
SDL_ShowWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SDL_PLATFORM_LINUX)
|
||||
// On Linux the progress state is persisted throughout multiple program runs, so reset state on window creation
|
||||
SDL_SetWindowProgressState(window, SDL_PROGRESS_STATE_NONE);
|
||||
SDL_SetWindowProgressValue(window, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool SDL_ContextNotSupported(const char *name)
|
||||
|
|
|
|||
|
|
@ -158,6 +158,17 @@ bool Cocoa_SetClipboardData(SDL_VideoDevice *_this)
|
|||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
|
||||
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
|
||||
|
||||
// SetClipboardText specialization so text is available after the app quits
|
||||
if (_this->clipboard_callback && _this->num_clipboard_mime_types == 1) {
|
||||
if (SDL_strncmp(_this->clipboard_mime_types[0], "text/plain;charset=utf-8", 24) == 0) {
|
||||
[pasteboard declareTypes:@[ NSPasteboardTypeString ] owner:nil];
|
||||
[pasteboard setString:@((char *)_this->clipboard_userdata) forType:NSPasteboardTypeString];
|
||||
data.clipboard_count = [pasteboard changeCount];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
NSPasteboardItem *newItem = [NSPasteboardItem new];
|
||||
NSMutableArray *utiTypes = [NSMutableArray new];
|
||||
Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata];
|
||||
|
|
|
|||
|
|
@ -450,12 +450,18 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
|
|||
// All events except NSEventTypeMouseExited can only happen if the window
|
||||
// has mouse focus, so we'll always set the focus even if we happen to miss
|
||||
// NSEventTypeMouseEntered, which apparently happens if the window is
|
||||
// created under the mouse on macOS 12.7
|
||||
// created under the mouse on macOS 12.7. But, only set the focus if
|
||||
// the event acutally has a non-NULL window, otherwise what would happen
|
||||
// is that after an NSEventTypeMouseEntered there would sometimes be
|
||||
// NSEventTypeMouseMoved without a window causing us to suppress subsequent
|
||||
// mouse move events.
|
||||
NSEventType event_type = [event type];
|
||||
if (event_type == NSEventTypeMouseExited) {
|
||||
Cocoa_MouseFocus = NULL;
|
||||
} else {
|
||||
Cocoa_MouseFocus = [event window];
|
||||
if ([event window] != NULL) {
|
||||
Cocoa_MouseFocus = [event window];
|
||||
}
|
||||
}
|
||||
|
||||
switch (event_type) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
#ifdef SDL_VIDEO_DRIVER_OPENVR
|
||||
|
||||
#if 0
|
||||
#define DEBUG_OPENVR
|
||||
#endif
|
||||
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
|
|
@ -445,7 +447,7 @@ static void OPENVR_VirtualControllerUpdate(void *userdata)
|
|||
static bool OPENVR_SetupJoystickBasedOnLoadedActionManifest(SDL_VideoData * videodata)
|
||||
{
|
||||
SDL_VirtualJoystickDesc desc;
|
||||
int virtual_index;
|
||||
SDL_JoystickID virtual_id;
|
||||
|
||||
EVRInputError e = 0;
|
||||
|
||||
|
|
@ -537,22 +539,22 @@ static bool OPENVR_SetupJoystickBasedOnLoadedActionManifest(SDL_VideoData * vide
|
|||
desc.RumbleTriggers = OPENVR_VirtualControllerRumbleTriggers;
|
||||
desc.Update = OPENVR_VirtualControllerUpdate;
|
||||
desc.userdata = videodata;
|
||||
virtual_index = SDL_AttachVirtualJoystick(&desc);
|
||||
virtual_id = SDL_AttachVirtualJoystick(&desc);
|
||||
|
||||
if (virtual_index < 0) {
|
||||
if (!virtual_id) {
|
||||
return SDL_SetError("OPENVR: Couldn't attach virtual joystick device: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
videodata->virtual_joystick = SDL_OpenJoystick(virtual_id);
|
||||
if (!videodata->virtual_joystick) {
|
||||
return SDL_SetError("OPENVR: Couldn't open virtual joystick device: %s", SDL_GetError());
|
||||
} else {
|
||||
videodata->virtual_joystick = SDL_OpenJoystick(virtual_index);
|
||||
if (!videodata->virtual_joystick) {
|
||||
return SDL_SetError("OPENVR: Couldn't open virtual joystick device: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_OPENVR
|
||||
SDL_Log("Loaded virtual joystick with %d buttons and %d axes", videodata->input_action_handles_buttons_count, videodata->input_action_handles_axes_count);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool OPENVR_InitializeOverlay(SDL_VideoDevice *_this,SDL_Window *window)
|
||||
|
|
@ -710,7 +712,7 @@ static bool OPENVR_ReleaseFrame(SDL_VideoDevice *_this)
|
|||
if (videodata->overlaytexture != 0 &&
|
||||
videodata->targh == videodata->last_targh &&
|
||||
videodata->targw == videodata->last_targw) {
|
||||
// Only submit frames to OpenVR if the textu re exists.
|
||||
// Only submit frames to OpenVR if the texture exists.
|
||||
struct Texture_t tex;
|
||||
|
||||
// Setup a Texture_t object to send in the texture.
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
// Scoped function declarations
|
||||
static void Wayland_SeatUpdateKeyboardGrab(SDL_WaylandSeat *seat);
|
||||
|
||||
struct SDL_WaylandTouchPoint
|
||||
typedef struct
|
||||
{
|
||||
SDL_TouchID id;
|
||||
wl_fixed_t fx;
|
||||
|
|
@ -98,11 +98,11 @@ struct SDL_WaylandTouchPoint
|
|||
struct wl_surface *surface;
|
||||
|
||||
struct wl_list link;
|
||||
};
|
||||
} SDL_WaylandTouchPoint;
|
||||
|
||||
static void Wayland_SeatAddTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_surface *surface)
|
||||
{
|
||||
struct SDL_WaylandTouchPoint *tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
|
||||
SDL_WaylandTouchPoint *tp = SDL_malloc(sizeof(SDL_WaylandTouchPoint));
|
||||
|
||||
SDL_zerop(tp);
|
||||
tp->id = id;
|
||||
|
|
@ -113,9 +113,37 @@ static void Wayland_SeatAddTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed
|
|||
WAYLAND_wl_list_insert(&seat->touch.points, &tp->link);
|
||||
}
|
||||
|
||||
static void Wayland_SeatCancelTouch(SDL_WaylandSeat *seat, SDL_WaylandTouchPoint *tp)
|
||||
{
|
||||
if (tp->surface) {
|
||||
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(tp->surface);
|
||||
|
||||
if (window_data) {
|
||||
const float x = (float)(wl_fixed_to_double(tp->fx) / window_data->current.logical_width);
|
||||
const float y = (float)(wl_fixed_to_double(tp->fy) / window_data->current.logical_height);
|
||||
|
||||
SDL_SendTouch(0, (SDL_TouchID)(uintptr_t)seat->touch.wl_touch,
|
||||
(SDL_FingerID)(tp->id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_CANCELED, x, y, 0.0f);
|
||||
|
||||
--window_data->active_touch_count;
|
||||
|
||||
/* If the window currently has mouse focus and has no currently active keyboards, pointers,
|
||||
* or touch events, then consider mouse focus to be lost.
|
||||
*/
|
||||
if (SDL_GetMouseFocus() == window_data->sdlwindow && !window_data->keyboard_focus_count &&
|
||||
!window_data->pointer_focus_count && !window_data->active_touch_count) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WAYLAND_wl_list_remove(&tp->link);
|
||||
SDL_free(tp);
|
||||
}
|
||||
|
||||
static void Wayland_SeatUpdateTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_surface **surface)
|
||||
{
|
||||
struct SDL_WaylandTouchPoint *tp;
|
||||
SDL_WaylandTouchPoint *tp;
|
||||
|
||||
wl_list_for_each (tp, &seat->touch.points, link) {
|
||||
if (tp->id == id) {
|
||||
|
|
@ -131,7 +159,7 @@ static void Wayland_SeatUpdateTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fi
|
|||
|
||||
static void Wayland_SeatRemoveTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed_t *fx, wl_fixed_t *fy, struct wl_surface **surface)
|
||||
{
|
||||
struct SDL_WaylandTouchPoint *tp;
|
||||
SDL_WaylandTouchPoint *tp;
|
||||
|
||||
wl_list_for_each (tp, &seat->touch.points, link) {
|
||||
if (tp->id == id) {
|
||||
|
|
@ -152,23 +180,6 @@ static void Wayland_SeatRemoveTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fi
|
|||
}
|
||||
}
|
||||
|
||||
static bool Wayland_SurfaceHasActiveTouches(SDL_VideoData *display, struct wl_surface *surface)
|
||||
{
|
||||
struct SDL_WaylandTouchPoint *tp;
|
||||
SDL_WaylandSeat *seat;
|
||||
|
||||
// Check all seats for active touches on the surface.
|
||||
wl_list_for_each (seat, &display->seat_list, link) {
|
||||
wl_list_for_each (tp, &seat->touch.points, link) {
|
||||
if (tp->surface == surface) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Wayland_GetScaledMouseRect(SDL_Window *window, SDL_Rect *scaled_rect)
|
||||
{
|
||||
SDL_WindowData *window_data = window->internal;
|
||||
|
|
@ -751,7 +762,7 @@ static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|||
*/
|
||||
SDL_Window *mouse_focus = SDL_GetMouseFocus();
|
||||
const bool had_focus = mouse_focus && window->sdlwindow == mouse_focus;
|
||||
if (!--window->pointer_focus_count && had_focus && !Wayland_SurfaceHasActiveTouches(seat->display, surface)) {
|
||||
if (!--window->pointer_focus_count && had_focus && !window->active_touch_count) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
|
||||
|
|
@ -901,7 +912,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
|
|||
*
|
||||
* The mouse is not captured in relative mode.
|
||||
*/
|
||||
if (!seat->display->relative_mode_enabled || !Wayland_SeatHasRelativePointerFocus(seat)) {
|
||||
if (!seat->pointer.relative_pointer) {
|
||||
if (seat->pointer.buttons_pressed != 0) {
|
||||
window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
||||
} else {
|
||||
|
|
@ -1153,30 +1164,23 @@ static void relative_pointer_handle_relative_motion(void *data,
|
|||
wl_fixed_t dy_unaccel_w)
|
||||
{
|
||||
SDL_WaylandSeat *seat = data;
|
||||
SDL_WindowData *window = seat->pointer.focus;
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
|
||||
if (seat->display->relative_mode_enabled) {
|
||||
SDL_WindowData *window = seat->pointer.focus;
|
||||
// Relative pointer event times are in microsecond granularity.
|
||||
const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
|
||||
|
||||
// Relative motion follows keyboard focus.
|
||||
if (Wayland_SeatHasRelativePointerFocus(seat)) {
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
|
||||
// Relative pointer event times are in microsecond granularity.
|
||||
const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
|
||||
|
||||
double dx;
|
||||
double dy;
|
||||
if (mouse->InputTransform || !mouse->enable_relative_system_scale) {
|
||||
dx = wl_fixed_to_double(dx_unaccel_w);
|
||||
dy = wl_fixed_to_double(dy_unaccel_w);
|
||||
} else {
|
||||
dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x;
|
||||
dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y;
|
||||
}
|
||||
|
||||
SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
|
||||
}
|
||||
double dx;
|
||||
double dy;
|
||||
if (mouse->InputTransform || !mouse->enable_relative_system_scale) {
|
||||
dx = wl_fixed_to_double(dx_unaccel_w);
|
||||
dy = wl_fixed_to_double(dy_unaccel_w);
|
||||
} else {
|
||||
dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x;
|
||||
dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y;
|
||||
}
|
||||
|
||||
SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
|
||||
}
|
||||
|
||||
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
|
||||
|
|
@ -1243,6 +1247,7 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
|
|||
y = (float)wl_fixed_to_double(fy) / (window_data->current.logical_height - 1);
|
||||
}
|
||||
|
||||
++window_data->active_touch_count;
|
||||
SDL_SetMouseFocus(window_data->sdlwindow);
|
||||
|
||||
SDL_SendTouch(Wayland_GetTouchTimestamp(seat, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
||||
|
|
@ -1269,11 +1274,13 @@ static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial
|
|||
SDL_SendTouch(Wayland_GetTouchTimestamp(seat, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
||||
(SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_UP, x, y, 0.0f);
|
||||
|
||||
/* If the window currently has mouse focus, the keyboard focus is another window or NULL, the window has no
|
||||
* pointers active on it, and the surface has no active touch events, then consider mouse focus to be lost.
|
||||
--window_data->active_touch_count;
|
||||
|
||||
/* If the window currently has mouse focus and has no currently active keyboards, pointers,
|
||||
* or touch events, then consider mouse focus to be lost.
|
||||
*/
|
||||
if (SDL_GetMouseFocus() == window_data->sdlwindow && seat->keyboard.focus != window_data &&
|
||||
!window_data->pointer_focus_count && !Wayland_SurfaceHasActiveTouches(seat->display, surface)) {
|
||||
if (SDL_GetMouseFocus() == window_data->sdlwindow && !window_data->keyboard_focus_count &&
|
||||
!window_data->pointer_focus_count && !window_data->active_touch_count) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
|
|
@ -1308,39 +1315,11 @@ static void touch_handler_frame(void *data, struct wl_touch *touch)
|
|||
static void touch_handler_cancel(void *data, struct wl_touch *touch)
|
||||
{
|
||||
SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
||||
struct SDL_WaylandTouchPoint *tp, *temp;
|
||||
SDL_WaylandTouchPoint *tp, *temp;
|
||||
|
||||
// Need the safe loop variant here as cancelling a touch point removes it from the list.
|
||||
wl_list_for_each_safe (tp, temp, &seat->touch.points, link) {
|
||||
bool removed = false;
|
||||
|
||||
if (tp->surface) {
|
||||
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(tp->surface);
|
||||
|
||||
if (window_data) {
|
||||
const float x = (float)(wl_fixed_to_double(tp->fx) / window_data->current.logical_width);
|
||||
const float y = (float)(wl_fixed_to_double(tp->fy) / window_data->current.logical_height);
|
||||
|
||||
SDL_SendTouch(0, (SDL_TouchID)(uintptr_t)touch,
|
||||
(SDL_FingerID)(tp->id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_CANCELED, x, y, 0.0f);
|
||||
|
||||
// Remove the touch from the list before checking for still-active touches on the surface.
|
||||
WAYLAND_wl_list_remove(&tp->link);
|
||||
removed = true;
|
||||
|
||||
/* If the window currently has mouse focus, the keyboard focus is another window or NULL, the window has no
|
||||
* pointers active on it, and the surface has no active touch events, then consider mouse focus to be lost.
|
||||
*/
|
||||
if (SDL_GetMouseFocus() == window_data->sdlwindow && seat->keyboard.focus != window_data &&
|
||||
!window_data->pointer_focus_count && !Wayland_SurfaceHasActiveTouches(seat->display, tp->surface)) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!removed) {
|
||||
WAYLAND_wl_list_remove(&tp->link);
|
||||
}
|
||||
SDL_free(tp);
|
||||
Wayland_SeatCancelTouch(seat, tp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1924,8 +1903,7 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|||
/* If the window has mouse focus, has no pointers within it, and no active touches, consider
|
||||
* mouse focus to be lost.
|
||||
*/
|
||||
if (SDL_GetMouseFocus() == window->sdlwindow && !window->pointer_focus_count &&
|
||||
!Wayland_SurfaceHasActiveTouches(seat->display, surface)) {
|
||||
if (SDL_GetMouseFocus() == window->sdlwindow && !window->pointer_focus_count && !window->active_touch_count) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
|
|
@ -2092,26 +2070,6 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
|||
keyboard_handle_repeat_info, // Version 4
|
||||
};
|
||||
|
||||
static void Wayland_SeatCreateRelativePointer(SDL_WaylandSeat *seat)
|
||||
{
|
||||
if (seat->display->relative_pointer_manager) {
|
||||
if (seat->pointer.wl_pointer && !seat->pointer.relative_pointer) {
|
||||
seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
|
||||
zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer,
|
||||
&relative_pointer_listener,
|
||||
seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display)
|
||||
{
|
||||
SDL_WaylandSeat *seat;
|
||||
wl_list_for_each(seat, &display->seat_list, link) {
|
||||
Wayland_SeatCreateRelativePointer(seat);
|
||||
}
|
||||
}
|
||||
|
||||
static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
|
||||
{
|
||||
// Make sure focus is removed from a surface before the pointer is destroyed.
|
||||
|
|
@ -2254,8 +2212,6 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum w
|
|||
wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
|
||||
wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
|
||||
|
||||
Wayland_SeatCreateRelativePointer(seat);
|
||||
|
||||
seat->pointer.sdl_id = SDL_GetNextObjectID();
|
||||
|
||||
if (seat->name) {
|
||||
|
|
@ -3416,6 +3372,36 @@ void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat,
|
|||
WAYLAND_wl_display_flush(display->display);
|
||||
}
|
||||
|
||||
void Wayland_DisplayRemoveWindowReferencesFromSeats(SDL_VideoData *display, SDL_WindowData *window)
|
||||
{
|
||||
SDL_WaylandSeat *seat;
|
||||
wl_list_for_each (seat, &display->seat_list, link)
|
||||
{
|
||||
if (seat->keyboard.focus == window) {
|
||||
keyboard_handle_leave(seat, seat->keyboard.wl_keyboard, 0, window->surface);
|
||||
}
|
||||
|
||||
if (seat->pointer.focus == window) {
|
||||
pointer_handle_leave(seat, seat->pointer.wl_pointer, 0, window->surface);
|
||||
}
|
||||
|
||||
// Need the safe loop variant here as cancelling a touch point removes it from the list.
|
||||
SDL_WaylandTouchPoint *tp, *temp;
|
||||
wl_list_for_each_safe (tp, temp, &seat->touch.points, link) {
|
||||
if (tp->surface == window->surface) {
|
||||
Wayland_SeatCancelTouch(seat, tp);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_WaylandPenTool *tool;
|
||||
wl_list_for_each (tool, &seat->tablet.tool_list, link) {
|
||||
if (tool->tool_focus == window->sdlwindow) {
|
||||
tablet_tool_handle_proximity_out(tool, tool->wltool);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events)
|
||||
{
|
||||
if (!seat) {
|
||||
|
|
@ -3475,16 +3461,36 @@ void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events)
|
|||
SDL_free(seat);
|
||||
}
|
||||
|
||||
bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat)
|
||||
static void Wayland_SeatUpdateRelativePointer(SDL_WaylandSeat *seat)
|
||||
{
|
||||
/* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
|
||||
* attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
|
||||
* focus on the window with pointer focus.
|
||||
*/
|
||||
if (seat->keyboard.wl_keyboard) {
|
||||
return seat->keyboard.focus && seat->keyboard.focus == seat->pointer.focus;
|
||||
} else {
|
||||
return seat->pointer.focus && seat->pointer.focus->keyboard_focus_count != 0;
|
||||
if (seat->display->relative_pointer_manager) {
|
||||
bool relative_focus = false;
|
||||
|
||||
if (seat->pointer.focus) {
|
||||
/* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
|
||||
* attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
|
||||
* focus on the window with pointer focus.
|
||||
*/
|
||||
if (seat->pointer.focus->sdlwindow->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE) {
|
||||
if (seat->keyboard.wl_keyboard) {
|
||||
relative_focus = seat->keyboard.focus == seat->pointer.focus;
|
||||
} else {
|
||||
relative_focus = seat->pointer.focus->keyboard_focus_count != 0;
|
||||
}
|
||||
} else {
|
||||
relative_focus = SDL_GetMouse()->warp_emulation_active;
|
||||
}
|
||||
}
|
||||
|
||||
if (relative_focus) {
|
||||
if (!seat->pointer.relative_pointer) {
|
||||
seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
|
||||
zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer, &relative_pointer_listener, seat);
|
||||
}
|
||||
} else if (seat->pointer.relative_pointer) {
|
||||
zwp_relative_pointer_v1_destroy(seat->pointer.relative_pointer);
|
||||
seat->pointer.relative_pointer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3517,11 +3523,10 @@ static void Wayland_SeatUpdateKeyboardGrab(SDL_WaylandSeat *seat)
|
|||
void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
|
||||
{
|
||||
SDL_VideoData *display = seat->display;
|
||||
Wayland_SeatUpdateRelativePointer(seat);
|
||||
|
||||
if (display->pointer_constraints) {
|
||||
const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
|
||||
|
||||
if (seat->pointer.locked_pointer && (!display->relative_mode_enabled || !has_relative_focus)) {
|
||||
if (seat->pointer.locked_pointer && !seat->pointer.relative_pointer) {
|
||||
zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
|
||||
seat->pointer.locked_pointer = NULL;
|
||||
|
||||
|
|
@ -3531,7 +3536,7 @@ void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
|
|||
|
||||
if (seat->pointer.wl_pointer) {
|
||||
// If relative mode is active, and the pointer focus matches the keyboard focus, lock it.
|
||||
if (seat->display->relative_mode_enabled && has_relative_focus) {
|
||||
if (seat->pointer.relative_pointer) {
|
||||
if (!seat->pointer.locked_pointer) {
|
||||
// Creating a lock on a surface with an active confinement region on the same seat is a protocol error.
|
||||
if (seat->pointer.confined_pointer) {
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@ extern int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
|
|||
|
||||
extern void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
|
||||
extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);
|
||||
|
|
@ -201,10 +200,10 @@ extern void Wayland_DisplayCreateTextInputManager(SDL_VideoData *d, uint32_t id)
|
|||
extern void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat, Uint32 id);
|
||||
extern void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events);
|
||||
|
||||
extern bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat);
|
||||
extern void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat);
|
||||
extern void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
||||
extern void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
||||
extern void Wayland_DisplayRemoveWindowReferencesFromSeats(SDL_VideoData *display, SDL_WindowData *window);
|
||||
|
||||
/* The implicit grab serial needs to be updated on:
|
||||
* - Keyboard key down/up
|
||||
|
|
|
|||
|
|
@ -881,8 +881,7 @@ static bool Wayland_WarpMouseRelative(SDL_Window *window, float x, float y)
|
|||
|
||||
if (d->pointer_constraints) {
|
||||
wl_list_for_each (seat, &d->seat_list, link) {
|
||||
if (wind == seat->pointer.focus ||
|
||||
(!seat->pointer.focus && wind == seat->keyboard.focus)) {
|
||||
if (wind == seat->pointer.focus) {
|
||||
Wayland_SeatWarpMouse(seat, wind, x, y);
|
||||
}
|
||||
}
|
||||
|
|
@ -939,7 +938,7 @@ static bool Wayland_SetRelativeMouseMode(bool enabled)
|
|||
return SDL_SetError("Failed to enable relative mode: compositor lacks support for the required zwp_pointer_constraints_v1 protocol");
|
||||
}
|
||||
|
||||
data->relative_mode_enabled = enabled;
|
||||
// Windows have a relative mode flag, so just update the grabs on a state change.
|
||||
Wayland_DisplayUpdatePointerGrabs(data, NULL);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1121,14 +1120,11 @@ void Wayland_SeatUpdateCursor(SDL_WaylandSeat *seat)
|
|||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
SDL_WindowData *pointer_focus = seat->pointer.focus;
|
||||
|
||||
if (pointer_focus) {
|
||||
const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
|
||||
|
||||
if (!seat->display->relative_mode_enabled || !has_relative_focus || !mouse->relative_mode_hide_cursor) {
|
||||
if (pointer_focus && mouse->cursor_visible) {
|
||||
if (!seat->pointer.relative_pointer || !mouse->relative_mode_hide_cursor) {
|
||||
const SDL_HitTestResult rc = pointer_focus->hit_test_result;
|
||||
|
||||
if ((seat->display->relative_mode_enabled && has_relative_focus) ||
|
||||
rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
|
||||
if (seat->pointer.relative_pointer || rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
|
||||
Wayland_SeatSetCursor(seat, mouse->cur_cursor);
|
||||
} else {
|
||||
Wayland_SeatSetCursor(seat, sys_cursors[rc]);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||
|
||||
#include "../../core/linux/SDL_system_theme.h"
|
||||
#include "../../core/linux/SDL_progressbar.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#include "SDL_waylandclipboard.h"
|
||||
|
|
@ -629,6 +630,9 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
|
|||
device->DestroyWindow = Wayland_DestroyWindow;
|
||||
device->SetWindowHitTest = Wayland_SetWindowHitTest;
|
||||
device->FlashWindow = Wayland_FlashWindow;
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
device->ApplyWindowProgress = DBUS_ApplyWindowProgress;
|
||||
#endif // SDL_USE_LIBDBUS
|
||||
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
|
||||
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
|
||||
device->SyncWindow = Wayland_SyncWindow;
|
||||
|
|
@ -1263,7 +1267,6 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
|
|||
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
||||
} else if (SDL_strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
|
||||
d->relative_pointer_manager = wl_registry_bind(d->registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
|
||||
Wayland_DisplayInitRelativePointerManager(d);
|
||||
} else if (SDL_strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
|
||||
d->pointer_constraints = wl_registry_bind(d->registry, id, &zwp_pointer_constraints_v1_interface, 1);
|
||||
} else if (SDL_strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) {
|
||||
|
|
|
|||
|
|
@ -96,9 +96,7 @@ struct SDL_VideoData
|
|||
int output_count;
|
||||
int output_max;
|
||||
|
||||
bool relative_mode_enabled;
|
||||
bool display_externally_owned;
|
||||
|
||||
bool scale_to_display_enabled;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2209,7 +2209,7 @@ static const struct xdg_activation_token_v1_listener activation_listener_xdg = {
|
|||
*
|
||||
* As you might expect from Wayland, the general policy is to go with #2 unless
|
||||
* the client can prove to the compositor beyond a reasonable doubt that raising
|
||||
* the window will not be malicuous behavior.
|
||||
* the window will not be malicious behavior.
|
||||
*
|
||||
* For SDL this means RaiseWindow and FlashWindow both use the same protocol,
|
||||
* but in different ways: RaiseWindow will provide as _much_ information as
|
||||
|
|
@ -3093,6 +3093,12 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
WAYLAND_wl_display_roundtrip(data->display);
|
||||
}
|
||||
|
||||
/* The compositor should have relinquished keyboard, pointer, touch, and tablet tool focus when the toplevel
|
||||
* window was destroyed upon being hidden, but there is no guarantee of this, so ensure that all references
|
||||
* to the window held by seats are released before destroying the underlying surface and struct.
|
||||
*/
|
||||
Wayland_DisplayRemoveWindowReferencesFromSeats(data, wind);
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (wind->egl_surface) {
|
||||
SDL_EGL_DestroySurface(_this, wind->egl_surface);
|
||||
|
|
|
|||
|
|
@ -132,9 +132,10 @@ struct SDL_WindowData
|
|||
struct Wayland_SHMBuffer *icon_buffers;
|
||||
int icon_buffer_count;
|
||||
|
||||
// Keyboard and pointer focus refcount.
|
||||
// Keyboard, pointer, and touch focus refcount.
|
||||
int keyboard_focus_count;
|
||||
int pointer_focus_count;
|
||||
int active_touch_count;
|
||||
|
||||
struct
|
||||
{
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ static bool WIN_SetClipboardText(SDL_VideoDevice *_this, const char *mime_type)
|
|||
clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, &clipboard_data_size);
|
||||
if (clipboard_data && clipboard_data_size > 0) {
|
||||
SIZE_T i, size;
|
||||
LPTSTR tstr = (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)clipboard_data, clipboard_data_size);
|
||||
LPWSTR tstr = (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)clipboard_data, clipboard_data_size);
|
||||
if (!tstr) {
|
||||
return SDL_SetError("Couldn't convert text from UTF-8");
|
||||
}
|
||||
|
|
@ -210,7 +210,7 @@ static bool WIN_SetClipboardText(SDL_VideoDevice *_this, const char *mime_type)
|
|||
// Save the data to the clipboard
|
||||
hMem = GlobalAlloc(GMEM_MOVEABLE, size);
|
||||
if (hMem) {
|
||||
LPTSTR dst = (LPTSTR)GlobalLock(hMem);
|
||||
LPWSTR dst = (LPWSTR)GlobalLock(hMem);
|
||||
if (dst) {
|
||||
// Copy the text over, adding carriage returns as necessary
|
||||
for (i = 0; tstr[i]; ++i) {
|
||||
|
|
|
|||
|
|
@ -1400,8 +1400,6 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static void WIN_UpdateDisplayMode(SDL_VideoDevice *_this, LPCWSTR deviceName, DW
|
|||
data->DeviceMode.dmFields = (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS);
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition): No simple way to extract the assignment
|
||||
if (index == ENUM_CURRENT_SETTINGS && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
|
||||
if (index == ENUM_CURRENT_SETTINGS && (hdc = CreateDCW(deviceName, NULL, NULL, NULL)) != NULL) {
|
||||
char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
|
||||
LPBITMAPINFO bmi;
|
||||
HBITMAP hbm;
|
||||
|
|
@ -158,7 +158,7 @@ static void WIN_ReleaseDXGIOutput(void *dxgi_output)
|
|||
#endif
|
||||
}
|
||||
|
||||
static SDL_DisplayOrientation WIN_GetNaturalOrientation(DEVMODE *mode)
|
||||
static SDL_DisplayOrientation WIN_GetNaturalOrientation(DEVMODEW *mode)
|
||||
{
|
||||
int width = mode->dmPelsWidth;
|
||||
int height = mode->dmPelsHeight;
|
||||
|
|
@ -177,7 +177,7 @@ static SDL_DisplayOrientation WIN_GetNaturalOrientation(DEVMODE *mode)
|
|||
}
|
||||
}
|
||||
|
||||
static SDL_DisplayOrientation WIN_GetDisplayOrientation(DEVMODE *mode)
|
||||
static SDL_DisplayOrientation WIN_GetDisplayOrientation(DEVMODEW *mode)
|
||||
{
|
||||
if (WIN_GetNaturalOrientation(mode) == SDL_ORIENTATION_LANDSCAPE) {
|
||||
switch (mode->dmDisplayOrientation) {
|
||||
|
|
@ -208,7 +208,7 @@ static SDL_DisplayOrientation WIN_GetDisplayOrientation(DEVMODE *mode)
|
|||
}
|
||||
}
|
||||
|
||||
static void WIN_GetRefreshRate(void *dxgi_output, DEVMODE *mode, int *numerator, int *denominator)
|
||||
static void WIN_GetRefreshRate(void *dxgi_output, DEVMODEW *mode, int *numerator, int *denominator)
|
||||
{
|
||||
// We're not currently using DXGI to query display modes, so fake NTSC timings
|
||||
switch (mode->dmDisplayFrequency) {
|
||||
|
|
@ -274,7 +274,7 @@ static float WIN_GetContentScale(SDL_VideoDevice *_this, HMONITOR hMonitor)
|
|||
static bool WIN_GetDisplayMode(SDL_VideoDevice *_this, void *dxgi_output, HMONITOR hMonitor, LPCWSTR deviceName, DWORD index, SDL_DisplayMode *mode, SDL_DisplayOrientation *natural_orientation, SDL_DisplayOrientation *current_orientation)
|
||||
{
|
||||
SDL_DisplayModeData *data;
|
||||
DEVMODE devmode;
|
||||
DEVMODEW devmode;
|
||||
|
||||
devmode.dmSize = sizeof(devmode);
|
||||
devmode.dmDriverExtra = 0;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ struct SDL_DisplayData
|
|||
|
||||
struct SDL_DisplayModeData
|
||||
{
|
||||
DEVMODE DeviceMode;
|
||||
DEVMODEW DeviceMode;
|
||||
};
|
||||
|
||||
extern bool WIN_InitModes(SDL_VideoDevice *_this);
|
||||
|
|
|
|||
|
|
@ -1450,7 +1450,7 @@ void *WIN_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t
|
|||
char *filename_utf8;
|
||||
void *iccProfileData = NULL;
|
||||
|
||||
filename_utf8 = WIN_StringToUTF8(data->ICMFileName);
|
||||
filename_utf8 = WIN_StringToUTF8W(data->ICMFileName);
|
||||
if (filename_utf8) {
|
||||
iccProfileData = SDL_LoadFile(filename_utf8, size);
|
||||
if (!iccProfileData) {
|
||||
|
|
@ -2061,7 +2061,7 @@ static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target,
|
|||
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p",
|
||||
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
|
||||
if (buffer) {
|
||||
buffer = WIN_StringToUTF8((const wchar_t *)buffer);
|
||||
buffer = WIN_StringToUTF8W((const wchar_t *)buffer);
|
||||
if (buffer) {
|
||||
const size_t lbuffer = SDL_strlen((const char *)buffer);
|
||||
SDL_LogTrace(SDL_LOG_CATEGORY_INPUT,
|
||||
|
|
@ -2208,8 +2208,8 @@ void WIN_AcceptDragAndDrop(SDL_Window *window, bool accept)
|
|||
drop_target->lpVtbl = vtDropTarget;
|
||||
drop_target->window = window;
|
||||
drop_target->hwnd = data->hwnd;
|
||||
drop_target->format_file = RegisterClipboardFormat(L"text/uri-list");
|
||||
drop_target->format_text = RegisterClipboardFormat(L"text/plain;charset=utf-8");
|
||||
drop_target->format_file = RegisterClipboardFormatW(L"text/uri-list");
|
||||
drop_target->format_text = RegisterClipboardFormatW(L"text/plain;charset=utf-8");
|
||||
data->drop_target = drop_target;
|
||||
SDLDropTarget_AddRef(drop_target);
|
||||
RegisterDragDrop(data->hwnd, (LPDROPTARGET)drop_target);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <unistd.h> // For getpid() and readlink()
|
||||
|
||||
#include "../../core/linux/SDL_system_theme.h"
|
||||
#include "../../core/linux/SDL_progressbar.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
|
|
@ -204,6 +205,9 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
|||
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
|
||||
device->UpdateWindowShape = X11_UpdateWindowShape;
|
||||
device->FlashWindow = X11_FlashWindow;
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
device->ApplyWindowProgress = DBUS_ApplyWindowProgress;
|
||||
#endif // SDL_USE_LIBDBUS
|
||||
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
|
||||
device->SetWindowFocusable = X11_SetWindowFocusable;
|
||||
device->SyncWindow = X11_SyncWindow;
|
||||
|
|
@ -280,7 +284,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);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
|
@ -102,6 +107,11 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if (print_arguments) {
|
||||
int print_i;
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
/* reopen stdout as binary to prevent newline conversion */
|
||||
_setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
|
||||
for (print_i = 0; i + print_i < argc; print_i++) {
|
||||
fprintf(stdout, "|%d=%s|\r\n", print_i, argv[i + print_i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ static int SDLCALL process_testArguments(void *arg)
|
|||
"",
|
||||
" ",
|
||||
"a b c",
|
||||
"a\tb\tc\t",
|
||||
"a\tb\tc\t\v\r\n",
|
||||
"\"a b\" c",
|
||||
"'a' 'b' 'c'",
|
||||
"%d%%%s",
|
||||
|
|
@ -965,6 +965,165 @@ cleanup:
|
|||
return TEST_COMPLETED;
|
||||
}
|
||||
|
||||
static int process_testWindowsCmdline(void *arg)
|
||||
{
|
||||
TestProcessData *data = (TestProcessData *)arg;
|
||||
const char *process_args[] = {
|
||||
data->childprocess_path,
|
||||
"--print-arguments",
|
||||
"--",
|
||||
"",
|
||||
" ",
|
||||
"a b c",
|
||||
"a\tb\tc\t",
|
||||
"\"a b\" c",
|
||||
"'a' 'b' 'c'",
|
||||
"%d%%%s",
|
||||
"\\t\\c",
|
||||
"evil\\",
|
||||
"a\\b\"c\\",
|
||||
"\"\\^&|<>%", /* characters with a special meaning */
|
||||
NULL
|
||||
};
|
||||
/* this will have the same result as process_args, but escaped in a different way */
|
||||
const char *process_cmdline_template =
|
||||
"%s "
|
||||
"--print-arguments "
|
||||
"-- "
|
||||
"\"\" "
|
||||
"\" \" "
|
||||
"a\" \"b\" \"c\t" /* using tab as delimiter */
|
||||
"\"a\tb\tc\t\" "
|
||||
"\"\"\"\"a b\"\"\" c\" "
|
||||
"\"'a' 'b' 'c'\" "
|
||||
"%%d%%%%%%s " /* will be passed to sprintf */
|
||||
"\\t\\c "
|
||||
"evil\\ "
|
||||
"a\\b\"\\\"\"c\\ "
|
||||
"\\\"\\^&|<>%%";
|
||||
char process_cmdline[65535];
|
||||
SDL_PropertiesID props;
|
||||
SDL_Process *process = NULL;
|
||||
char *buffer;
|
||||
int exit_code;
|
||||
int i;
|
||||
size_t total_read = 0;
|
||||
|
||||
#ifndef SDL_PLATFORM_WINDOWS
|
||||
SDLTest_AssertPass("SDL_PROP_PROCESS_CREATE_CMDLINE_STRING only works on Windows");
|
||||
return TEST_SKIPPED;
|
||||
#endif
|
||||
|
||||
props = SDL_CreateProperties();
|
||||
SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()");
|
||||
if (!props) {
|
||||
goto failed;
|
||||
}
|
||||
SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN, true);
|
||||
|
||||
process = SDL_CreateProcessWithProperties(props);
|
||||
SDLTest_AssertCheck(process == NULL, "SDL_CreateProcessWithProperties() should fail");
|
||||
|
||||
SDL_snprintf(process_cmdline, SDL_arraysize(process_cmdline), process_cmdline_template, data->childprocess_path);
|
||||
SDL_SetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, process_cmdline);
|
||||
|
||||
process = SDL_CreateProcessWithProperties(props);
|
||||
SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()");
|
||||
if (!process) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
exit_code = 0xdeadbeef;
|
||||
buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code);
|
||||
SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()");
|
||||
SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code);
|
||||
if (!buffer) {
|
||||
goto failed;
|
||||
}
|
||||
SDLTest_LogEscapedString("stdout of process: ", buffer, total_read);
|
||||
|
||||
for (i = 3; process_args[i]; i++) {
|
||||
char line[64];
|
||||
SDL_snprintf(line, sizeof(line), "|%d=%s|", i - 3, process_args[i]);
|
||||
SDLTest_AssertCheck(!!SDL_strstr(buffer, line), "Check %s is in output", line);
|
||||
}
|
||||
SDL_free(buffer);
|
||||
|
||||
SDLTest_AssertPass("About to destroy process");
|
||||
SDL_DestroyProcess(process);
|
||||
|
||||
return TEST_COMPLETED;
|
||||
|
||||
failed:
|
||||
SDL_DestroyProcess(process);
|
||||
return TEST_ABORTED;
|
||||
}
|
||||
|
||||
static int process_testWindowsCmdlinePrecedence(void *arg)
|
||||
{
|
||||
TestProcessData *data = (TestProcessData *)arg;
|
||||
const char *process_args[] = {
|
||||
data->childprocess_path,
|
||||
"--print-arguments",
|
||||
"--",
|
||||
"argument 1",
|
||||
NULL
|
||||
};
|
||||
const char *process_cmdline_template = "%s --print-arguments -- \"argument 2\"";
|
||||
char process_cmdline[65535];
|
||||
SDL_PropertiesID props;
|
||||
SDL_Process *process = NULL;
|
||||
char *buffer;
|
||||
int exit_code;
|
||||
size_t total_read = 0;
|
||||
|
||||
#ifndef SDL_PLATFORM_WINDOWS
|
||||
SDLTest_AssertPass("SDL_PROP_PROCESS_CREATE_CMDLINE_STRING only works on Windows");
|
||||
return TEST_SKIPPED;
|
||||
#endif
|
||||
|
||||
props = SDL_CreateProperties();
|
||||
SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()");
|
||||
if (!props) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
SDL_snprintf(process_cmdline, SDL_arraysize(process_cmdline), process_cmdline_template, data->childprocess_path);
|
||||
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args);
|
||||
SDL_SetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, (const char *)process_cmdline);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN, true);
|
||||
|
||||
process = SDL_CreateProcessWithProperties(props);
|
||||
SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()");
|
||||
if (!process) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
exit_code = 0xdeadbeef;
|
||||
buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code);
|
||||
SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()");
|
||||
SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code);
|
||||
if (!buffer) {
|
||||
goto failed;
|
||||
}
|
||||
SDLTest_LogEscapedString("stdout of process: ", buffer, total_read);
|
||||
SDLTest_AssertCheck(!!SDL_strstr(buffer, "|0=argument 2|"), "Check |0=argument 2| is printed");
|
||||
SDL_free(buffer);
|
||||
|
||||
SDLTest_AssertPass("About to destroy process");
|
||||
SDL_DestroyProcess(process);
|
||||
|
||||
return TEST_COMPLETED;
|
||||
|
||||
failed:
|
||||
SDL_DestroyProcess(process);
|
||||
return TEST_ABORTED;
|
||||
}
|
||||
|
||||
static const SDLTest_TestCaseReference processTestArguments = {
|
||||
process_testArguments, "process_testArguments", "Test passing arguments to child process", TEST_ENABLED
|
||||
};
|
||||
|
|
@ -1017,6 +1176,14 @@ static const SDLTest_TestCaseReference processTestFileRedirection = {
|
|||
process_testFileRedirection, "process_testFileRedirection", "Test redirection from/to files", TEST_ENABLED
|
||||
};
|
||||
|
||||
static const SDLTest_TestCaseReference processTestWindowsCmdline = {
|
||||
process_testWindowsCmdline, "process_testWindowsCmdline", "Test passing cmdline directly to CreateProcess", TEST_ENABLED
|
||||
};
|
||||
|
||||
static const SDLTest_TestCaseReference processTestWindowsCmdlinePrecedence = {
|
||||
process_testWindowsCmdlinePrecedence, "process_testWindowsCmdlinePrecedence", "Test SDL_PROP_PROCESS_CREATE_CMDLINE_STRING precedence over SDL_PROP_PROCESS_CREATE_ARGS_POINTER", TEST_ENABLED
|
||||
};
|
||||
|
||||
static const SDLTest_TestCaseReference *processTests[] = {
|
||||
&processTestArguments,
|
||||
&processTestExitCode,
|
||||
|
|
@ -1031,6 +1198,8 @@ static const SDLTest_TestCaseReference *processTests[] = {
|
|||
&processTestNonExistingExecutable,
|
||||
&processTestBatBadButVulnerability,
|
||||
&processTestFileRedirection,
|
||||
&processTestWindowsCmdline,
|
||||
&processTestWindowsCmdlinePrecedence,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue