deps: update to SDL 3.2.20 (#4007)

This commit is contained in:
Tyler Wilding
2025-08-23 20:13:35 -04:00
committed by GitHub
parent bbac33a8ae
commit 899d0b5dce
97 changed files with 1092 additions and 590 deletions
+9 -2
View File
@@ -174,6 +174,7 @@ class JobDetails:
brew_packages: list[str] = dataclasses.field(default_factory=list)
cmake_toolchain_file: str = ""
cmake_arguments: list[str] = dataclasses.field(default_factory=list)
cmake_generator: str = "Ninja"
cmake_build_arguments: list[str] = dataclasses.field(default_factory=list)
clang_tidy: bool = True
cppflags: list[str] = dataclasses.field(default_factory=list)
@@ -222,6 +223,7 @@ class JobDetails:
check_sources: bool = False
setup_python: bool = False
pypi_packages: list[str] = dataclasses.field(default_factory=list)
binutils_strings: str = "strings"
def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]:
data = {
@@ -255,6 +257,7 @@ class JobDetails:
"cflags": my_shlex_join(self.cppflags + self.cflags),
"cxxflags": my_shlex_join(self.cppflags + self.cxxflags),
"ldflags": my_shlex_join(self.ldflags),
"cmake-generator": self.cmake_generator,
"cmake-toolchain-file": self.cmake_toolchain_file,
"clang-tidy": self.clang_tidy,
"cmake-arguments": my_shlex_join(self.cmake_arguments),
@@ -289,6 +292,7 @@ class JobDetails:
"check-sources": self.check_sources,
"setup-python": self.setup_python,
"pypi-packages": my_shlex_join(self.pypi_packages),
"binutils-strings": self.binutils_strings,
}
return {k: v for k, v in data.items() if v != ""}
@@ -675,13 +679,16 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
job.shared_lib = SharedLibType.SO_0
job.static_lib = StaticLibType.A
case SdlPlatform.N3ds:
job.ccache = True
job.cmake_generator = "Unix Makefiles"
job.cmake_build_arguments.append("-j$(nproc)")
job.ccache = False
job.shared = False
job.apt_packages = ["ccache", "ninja-build", "binutils"]
job.apt_packages = []
job.clang_tidy = False
job.run_tests = False
job.cc_from_cmake = True
job.cmake_toolchain_file = "${DEVKITPRO}/cmake/3DS.cmake"
job.binutils_strings = "/opt/devkitpro/devkitARM/bin/arm-none-eabi-strings"
job.static_lib = StaticLibType.A
case SdlPlatform.Msys2:
job.ccache = True
+3 -3
View File
@@ -201,7 +201,7 @@ jobs:
#shell: ${{ matrix.platform.shell }}
run: |
${{ matrix.platform.source-cmd }}
${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -GNinja \
${{ matrix.platform.cmake-config-emulator }} cmake -S . -B build -G "${{ matrix.platform.cmake-generator }}" \
-Wdeprecated -Wdev -Werror \
${{ matrix.platform.cmake-toolchain-file != '' && format('-DCMAKE_TOOLCHAIN_FILE={0}', matrix.platform.cmake-toolchain-file) || '' }} \
-DSDL_WERROR=${{ matrix.platform.werror }} \
@@ -232,9 +232,9 @@ jobs:
run: |
echo "This should show us the SDL_REVISION"
echo "Shared library:"
${{ (matrix.platform.shared-lib && format('strings build/{0} | grep "Github Workflow"', matrix.platform.shared-lib)) || 'echo "<Shared library not supported by platform>"' }}
${{ (matrix.platform.shared-lib && format('{0} build/{1} | grep "Github Workflow"', matrix.platform.binutils-strings, matrix.platform.shared-lib)) || 'echo "<Shared library not supported by platform>"' }}
echo "Static library:"
${{ (matrix.platform.static-lib && format('strings build/{0} | grep "Github Workflow"', matrix.platform.static-lib)) || 'echo "<Static library not supported by platform>"' }}
${{ (matrix.platform.static-lib && format('{0} build/{1} | grep "Github Workflow"', matrix.platform.binutils-strings, matrix.platform.static-lib)) || 'echo "<Static library not supported by platform>"' }}
- name: 'Run build-time tests (CMake)'
id: tests
if: ${{ !matrix.platform.no-cmake && matrix.platform.run-tests }}
+1 -1
View File
@@ -256,7 +256,7 @@ jobs:
msvc:
needs: [src]
runs-on: windows-2019
runs-on: windows-2025
outputs:
VC-x86: ${{ steps.releaser.outputs.VC-x86 }}
VC-x64: ${{ steps.releaser.outputs.VC-x64 }}
Generated Vendored
+4
View File
@@ -107,6 +107,10 @@ LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroid
LOCAL_LDFLAGS := -Wl,--no-undefined -Wl,--no-undefined-version -Wl,--version-script=$(LOCAL_PATH)/src/dynapi/SDL_dynapi.sym
# https://developer.android.com/guide/practices/page-sizes
LOCAL_LDFLAGS += "-Wl,-z,max-page-size=16384"
LOCAL_LDFLAGS += "-Wl,-z,common-page-size=16384"
ifeq ($(NDK_DEBUG),1)
cmd-strip :=
endif
+16 -5
View File
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
endif()
# See docs/release_checklist.md
project(SDL3 LANGUAGES C VERSION "3.2.16")
project(SDL3 LANGUAGES C VERSION "3.2.20")
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(SDL3_MAINPROJECT ON)
@@ -188,9 +188,12 @@ if(MSVC)
# Make sure /RTC1 is disabled, otherwise it will use functions from the CRT
foreach(flag_var
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
string(REGEX REPLACE "/RTC(su|[1su])" "" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
set(CMAKE_MSVC_RUNTIME_CHECKS "")
endif()
if(MSVC_CLANG)
@@ -634,6 +637,11 @@ if(MSVC)
# Mark SDL3.dll as compatible with Control-flow Enforcement Technology (CET)
sdl_shared_link_options("-CETCOMPAT")
endif()
# for VS >= 17.14 targeting ARM64: inline the Interlocked funcs
if(MSVC_VERSION GREATER 1943 AND SDL_CPU_ARM64 AND NOT SDL_LIBC)
sdl_compile_options(PRIVATE "/forceInterlockedFunctions-")
endif()
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
@@ -1336,9 +1344,7 @@ if(ANDROID)
set(HAVE_SDL_HAPTIC TRUE)
endif()
if(SDL_HIDAPI)
CheckHIDAPI()
endif()
CheckHIDAPI()
if(SDL_JOYSTICK)
set(SDL_JOYSTICK_ANDROID 1)
@@ -1481,6 +1487,11 @@ if(ANDROID)
endif()
endif()
if(TARGET SDL3-shared)
target_link_options(SDL3-shared PRIVATE "-Wl,-z,max-page-size=16384")
target_link_options(SDL3-shared PRIVATE "-Wl,-z,common-page-size=16384")
endif()
elseif(EMSCRIPTEN)
# Hide noisy warnings that intend to aid mostly during initial stages of porting a new
# project. Uncomment at will for verbose cross-compiling -I/../ path info.
+2 -2
View File
@@ -19,10 +19,10 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.2.16</string>
<string>3.2.20</string>
<key>CFBundleSignature</key>
<string>SDLX</string>
<key>CFBundleVersion</key>
<string>3.2.16</string>
<string>3.2.20</string>
</dict>
</plist>
+4 -4
View File
@@ -3086,7 +3086,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
DEPLOYMENT_POSTPROCESSING = YES;
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
DYLIB_CURRENT_VERSION = 201.16.0;
DYLIB_CURRENT_VERSION = 201.20.0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_ALTIVEC_EXTENSIONS = YES;
@@ -3121,7 +3121,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 3.2.16;
MARKETING_VERSION = 3.2.20;
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
PRODUCT_NAME = SDL3;
@@ -3150,7 +3150,7 @@
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
DYLIB_CURRENT_VERSION = 201.16.0;
DYLIB_CURRENT_VERSION = 201.20.0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -3182,7 +3182,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 3.2.16;
MARKETING_VERSION = 3.2.20;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
+1 -1
View File
@@ -1,4 +1,4 @@
Title SDL 3.2.16
Title SDL 3.2.20
Version 1
Description SDL Library for macOS (http://www.libsdl.org)
DefaultLocation /Library/Frameworks
+1 -1
View File
@@ -19,7 +19,7 @@ android {
abiFilters 'arm64-v8a'
}
cmake {
arguments "-DANDROID_PLATFORM=android-21", "-DANDROID_STL=c++_static"
arguments "-DANDROID_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DAPP_SUPPORT_FLEXIBLE_PAGE_SIZES=true"
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
abiFilters 'arm64-v8a'
}
+4 -1
View File
@@ -7,4 +7,7 @@
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
# Min runtime API level
APP_PLATFORM=android-16
APP_PLATFORM=android-21
# https://developer.android.com/guide/practices/page-sizes#update-packaging
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
+5
View File
@@ -26,4 +26,9 @@ endif()
add_library(main SHARED
YourSourceHere.c
)
#https://developer.android.com/guide/practices/page-sizes#update-packaging
target_link_options(main PRIVATE "-Wl,-z,max-page-size=16384")
target_link_options(main PRIVATE "-Wl,-z,common-page-size=16384")
target_link_libraries(main PRIVATE SDL3::SDL3)
@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
private static final String TAG = "SDL";
private static final int SDL_MAJOR_VERSION = 3;
private static final int SDL_MINOR_VERSION = 2;
private static final int SDL_MICRO_VERSION = 16;
private static final int SDL_MICRO_VERSION = 20;
/*
// Display InputType.SOURCE/CLASS of events and devices
//
+7
View File
@@ -30,6 +30,7 @@ abi="arm64-v8a" # "armeabi-v7a arm64-v8a x86 x86_64"
obj=
lib=
ndk_args=
flexpage=true
# Allow an external caller to specify locations and platform.
while [ $# -gt 0 ]; do
@@ -42,6 +43,8 @@ while [ $# -gt 0 ]; do
platform=${arg#APP_PLATFORM=}
elif [ "${arg:0:8}" == "APP_ABI=" ]; then
abi=${arg#APP_ABI=}
elif [ "${arg:0:32}" == "APP_SUPPORT_FLEXIBLE_PAGE_SIZES=" ]; then
flexpage=${arg#APP_SUPPORT_FLEXIBLE_PAGE_SIZES=}
else
ndk_args="$ndk_args $arg"
fi
@@ -67,6 +70,9 @@ done
# APP_* variables set in the environment here will not be seen by the
# ndk-build makefile segments that use them, e.g., default-application.mk.
# For consistency, pass all values on the command line.
#
# Add support for Google Play 16 KB Page size requirement:
# https://developer.android.com/guide/practices/page-sizes#ndk-build
ndk-build \
NDK_PROJECT_PATH=null \
NDK_OUT=$obj \
@@ -75,4 +81,5 @@ ndk-build \
APP_ABI="$abi" \
APP_PLATFORM="$platform" \
APP_MODULES="SDL3" \
APP_SUPPORT_FLEXIBLE_PAGE_SIZES="$flexpage" \
$ndk_args
+8 -8
View File
@@ -1077,6 +1077,14 @@ endmacro()
# Check for HIDAPI support
macro(CheckHIDAPI)
if(ANDROID)
enable_language(CXX)
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
endif()
if(IOS OR TVOS)
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
endif()
if(SDL_HIDAPI)
set(HAVE_HIDAPI ON)
if(SDL_HIDAPI_LIBUSB)
@@ -1109,14 +1117,6 @@ macro(CheckHIDAPI)
endif()
if(HAVE_HIDAPI)
if(ANDROID)
enable_language(CXX)
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/android/hid.cpp")
endif()
if(IOS OR TVOS)
sdl_sources("${SDL3_SOURCE_DIR}/src/hidapi/ios/hid.m")
set(SDL_FRAMEWORK_COREBLUETOOTH 1)
endif()
set(HAVE_SDL_HIDAPI TRUE)
if(SDL_JOYSTICK AND SDL_HIDAPI_JOYSTICK)
+2 -2
View File
@@ -49,7 +49,7 @@ NSApplicationDelegate implementation:
```objc
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
if (SDL_GetEventState(SDL_EVENT_QUIT) == SDL_ENABLE) {
if (SDL_EventEnabled(SDL_EVENT_QUIT)) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_QUIT;
@@ -61,7 +61,7 @@ NSApplicationDelegate implementation:
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
if (SDL_GetEventState(SDL_EVENT_DROP_FILE) == SDL_ENABLE) {
if (SDL_EventEnabled(SDL_EVENT_DROP_FILE)) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_DROP_FILE;
+1 -1
View File
@@ -20,7 +20,7 @@
*/
/**
* Main include header for the SDL library, version 3.2.16
* Main include header for the SDL library, version 3.2.20
*
* It is almost always best to include just this one header instead of
* picking out individual headers included here. There are exceptions to
+1 -1
View File
@@ -362,7 +362,7 @@ extern SDL_DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *
#define SDL_enabled_assert(condition) \
do { \
while ( !(condition) ) { \
static struct SDL_AssertData sdl_assert_data = { 0, 0, #condition, 0, 0, 0, 0 }; \
static struct SDL_AssertData sdl_assert_data = { false, 0, #condition, NULL, 0, NULL, NULL }; \
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
continue; /* go again. */ \
+5 -2
View File
@@ -942,7 +942,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID devid);
* Binding a stream to a device will set its output format for playback
* devices, and its input format for recording devices, so they match the
* device's settings. The caller is welcome to change the other end of the
* stream's format at any time with SDL_SetAudioStreamFormat().
* stream's format at any time with SDL_SetAudioStreamFormat(). If the other
* end of the stream's format has never been set (the audio stream was created
* with a NULL audio spec), this function will set it to match the device
* end's format.
*
* \param devid an audio device to bind a stream to.
* \param streams an array of audio streams to bind.
@@ -1021,7 +1024,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnbindAudioStream(SDL_AudioStream *stream);
/**
* Query an audio stream for its currently-bound device.
*
* This reports the audio device that an audio stream is currently bound to.
* This reports the logical audio device that an audio stream is currently bound to.
*
* If not bound, or invalid, this returns zero, which is not a valid device
* ID.
+14 -14
View File
@@ -106,7 +106,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardText(const char *text);
/**
* Get UTF-8 text from the clipboard.
*
* This functions returns an empty string if there was not enough memory left
* This function returns an empty string if there is not enough memory left
* for a copy of the clipboard's content.
*
* \returns the clipboard text on success or an empty string on failure; call
@@ -155,7 +155,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetPrimarySelectionText(const char *text);
/**
* Get UTF-8 text from the primary selection.
*
* This functions returns an empty string if there was not enough memory left
* This function returns an empty string if there is not enough memory left
* for a copy of the primary selection's content.
*
* \returns the primary selection text on success or an empty string on
@@ -194,15 +194,15 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void);
* clipboard is cleared or new data is set. The clipboard is automatically
* cleared in SDL_Quit().
*
* \param userdata a pointer to provided user data.
* \param userdata a pointer to the provided user data.
* \param mime_type the requested mime-type.
* \param size a pointer filled in with the length of the returned data.
* \returns a pointer to the data for the provided mime-type. Returning NULL
* or setting length to 0 will cause no data to be sent to the
* or setting the length to 0 will cause no data to be sent to the
* "receiver". It is up to the receiver to handle this. Essentially
* returning no data is more or less undefined behavior and may cause
* breakage in receiving applications. The returned data will not be
* freed so it needs to be retained and dealt with internally.
* freed, so it needs to be retained and dealt with internally.
*
* \since This function is available since SDL 3.2.0.
*
@@ -211,10 +211,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void);
typedef const void *(SDLCALL *SDL_ClipboardDataCallback)(void *userdata, const char *mime_type, size_t *size);
/**
* Callback function that will be called when the clipboard is cleared, or new
* Callback function that will be called when the clipboard is cleared, or when new
* data is set.
*
* \param userdata a pointer to provided user data.
* \param userdata a pointer to the provided user data.
*
* \since This function is available since SDL 3.2.0.
*
@@ -231,7 +231,7 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
* respond with the data for the requested mime-type.
*
* The size of text data does not include any terminator, and the text does
* not need to be null terminated (e.g. you can directly copy a portion of a
* not need to be null-terminated (e.g., you can directly copy a portion of a
* document).
*
* \param callback a function pointer to the function that provides the
@@ -239,7 +239,7 @@ typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
* \param cleanup a function pointer to the function that cleans up the
* clipboard data.
* \param userdata an opaque pointer that will be forwarded to the callbacks.
* \param mime_types a list of mime-types that are being offered.
* \param mime_types a list of mime-types that are being offered. SDL copies the given list.
* \param num_mime_types the number of mime-types in the mime_types list.
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
@@ -269,10 +269,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback
extern SDL_DECLSPEC bool SDLCALL SDL_ClearClipboardData(void);
/**
* Get the data from clipboard for a given mime type.
* Get the data from the clipboard for a given mime type.
*
* The size of text data does not include the terminator, but the text is
* guaranteed to be null terminated.
* guaranteed to be null-terminated.
*
* \param mime_type the mime type to read from the clipboard.
* \param size a pointer filled in with the length of the returned data.
@@ -292,8 +292,8 @@ extern SDL_DECLSPEC void * SDLCALL SDL_GetClipboardData(const char *mime_type, s
/**
* Query whether there is data in the clipboard for the provided mime type.
*
* \param mime_type the mime type to check for data for.
* \returns true if there exists data in clipboard for the provided mime type,
* \param mime_type the mime type to check for data.
* \returns true if data exists in the clipboard for the provided mime type,
* false if it does not.
*
* \threadsafety This function should only be called on the main thread.
@@ -310,7 +310,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardData(const char *mime_type);
*
* \param num_mime_types a pointer filled with the number of mime types, may
* be NULL.
* \returns a null terminated array of strings with mime types, or NULL on
* \returns a null-terminated array of strings with mime types, or NULL on
* failure; call SDL_GetError() for more information. This should be
* freed with SDL_free() when it is no longer needed.
*
+1 -1
View File
@@ -486,7 +486,7 @@ SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; }
*
* \since This function is available since SDL 3.2.0.
*/
SDL_FORCE_INLINE Uint32 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
/**
* Swap a 16-bit value from littleendian to native byte order.
+1 -1
View File
@@ -1549,7 +1549,7 @@ typedef struct SDL_GPUSamplerCreateInfo
typedef struct SDL_GPUVertexBufferDescription
{
Uint32 slot; /**< The binding slot of the vertex buffer. */
Uint32 pitch; /**< The byte pitch between consecutive elements of the vertex buffer. */
Uint32 pitch; /**< The size of a single element + the offset between elements. */
SDL_GPUVertexInputRate input_rate; /**< Whether attribute addressing is a function of the vertex index or instance index. */
Uint32 instance_step_rate; /**< Reserved for future use. Must be set to 0. */
} SDL_GPUVertexBufferDescription;
+1 -1
View File
@@ -208,7 +208,7 @@ typedef enum SDL_Scancode
SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO
* keyboards have over ANSI ones,
* located between left shift and Y.
* located between left shift and Z.
* Produces GRAVE ACCENT and TILDE in a
* US or UK Mac layout, REVERSE SOLIDUS
* (backslash) and VERTICAL LINE in a
+1 -1
View File
@@ -62,7 +62,7 @@ extern "C" {
*
* \since This macro is available since SDL 3.2.0.
*/
#define SDL_MICRO_VERSION 16
#define SDL_MICRO_VERSION 20
/**
* This macro turns the version numbers into a numeric value.
+13
View File
@@ -1167,6 +1167,15 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int
* Popup windows implicitly do not have a border/decorations and do not appear
* on the taskbar/dock or in lists of windows such as alt-tab menus.
*
* By default, popup window positions will automatically be constrained to keep
* the entire window within display bounds. This can be overridden with the
* `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN` property.
*
* By default, popup menus will automatically grab keyboard focus from the parent
* when shown. This behavior can be overridden by setting the `SDL_WINDOW_NOT_FOCUSABLE`
* flag, setting the `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN` property to false, or
* toggling it after creation via the `SDL_SetWindowFocusable()` function.
*
* If a parent window is hidden or destroyed, any child popup windows will be
* recursively hidden or destroyed as well. Child popup windows not explicitly
* hidden will be restored when the parent is shown.
@@ -1207,6 +1216,9 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
* be always on top
* - `SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN`: true if the window has no
* window decoration
* - `SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN`: true if the "tooltip" and
* "menu" window types should be automatically constrained to be entirely within
* display bounds (default), false if no constraints on the position are desired.
* - `SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN`: true if the
* window will be used with an externally managed graphics context.
* - `SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN`: true if the window should
@@ -1321,6 +1333,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop
#define SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN "SDL.window.create.always_on_top"
#define SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN "SDL.window.create.borderless"
#define SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN "SDL.window.create.constrain_popup"
#define SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN "SDL.window.create.focusable"
#define SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN "SDL.window.create.external_graphics_context"
#define SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER "SDL.window.create.flags"
+3 -3
View File
@@ -51,14 +51,14 @@
extern "C" {
#endif
/* Avoid including vulkan.h, don't define VkInstance if it's already included */
#ifdef VULKAN_H_
/* Avoid including vulkan_core.h, don't define VkInstance if it's already included */
#ifdef VULKAN_CORE_H_
#define NO_SDL_VULKAN_TYPEDEFS
#endif
#ifndef NO_SDL_VULKAN_TYPEDEFS
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64)
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
#else
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
+4 -7
View File
@@ -111,6 +111,9 @@ typedef unsigned int uintptr_t;
# define SDL_DISABLE_AVX 1
#endif
#define HAVE_STDARG_H 1
#define HAVE_STDDEF_H 1
/* This can be disabled to avoid C runtime dependencies and manifest requirements */
#ifndef HAVE_LIBC
#define HAVE_LIBC 1
@@ -122,8 +125,6 @@ typedef unsigned int uintptr_t;
#define HAVE_LIMITS_H 1
#define HAVE_MATH_H 1
#define HAVE_SIGNAL_H 1
#define HAVE_STDARG_H 1
#define HAVE_STDDEF_H 1
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
@@ -153,7 +154,6 @@ typedef unsigned int uintptr_t;
#define HAVE_STRCMP 1
#define HAVE_STRNCMP 1
#define HAVE_STRPBRK 1
#define HAVE_VSSCANF 1
#define HAVE_VSNPRINTF 1
#define HAVE_ACOS 1
#define HAVE_ASIN 1
@@ -211,10 +211,7 @@ typedef unsigned int uintptr_t;
#if _MSC_VER >= 1400
#define HAVE__FSEEKI64 1
#endif
#endif /* _MSC_VER */
#else
#define HAVE_STDARG_H 1
#define HAVE_STDDEF_H 1
#endif /* _MSC_VER */
#endif
/* Enable various audio drivers */
Generated Vendored
+3 -3
View File
@@ -65,7 +65,7 @@
// Initialization/Cleanup routines
#include "timer/SDL_timer_c.h"
#ifdef SDL_VIDEO_DRIVER_WINDOWS
#ifdef SDL_PLATFORM_WINDOWS
extern bool SDL_HelperWindowCreate(void);
extern void SDL_HelperWindowDestroy(void);
#endif
@@ -317,7 +317,7 @@ bool SDL_InitSubSystem(SDL_InitFlags flags)
SDL_DBus_Init();
#endif
#ifdef SDL_VIDEO_DRIVER_WINDOWS
#ifdef SDL_PLATFORM_WINDOWS
if (flags & (SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK)) {
if (!SDL_HelperWindowCreate()) {
goto quit_and_error;
@@ -653,7 +653,7 @@ void SDL_Quit(void)
SDL_bInMainQuit = true;
// Quit all subsystems
#ifdef SDL_VIDEO_DRIVER_WINDOWS
#ifdef SDL_PLATFORM_WINDOWS
SDL_HelperWindowDestroy();
#endif
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
+29 -9
View File
@@ -1153,7 +1153,10 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
// We should have updated this elsewhere if the format changed!
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec, NULL, NULL));
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
const int br = SDL_GetAtomicInt(&logdev->paused) ? 0 : SDL_GetAudioStreamDataAdjustGain(stream, device_buffer, buffer_size, logdev->gain);
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
failed = true;
SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
@@ -1195,6 +1198,8 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
// We should have updated this elsewhere if the format changed!
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &outspec, NULL, NULL));
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
/* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
for iterating here because the binding linked list can only change while the device lock is held.
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
@@ -1330,6 +1335,7 @@ bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
SDL_assert(stream->src_spec.format == ((logdev->postmix || (logdev->gain != 1.0f)) ? SDL_AUDIO_F32 : device->spec.format));
SDL_assert(stream->src_spec.channels == device->spec.channels);
SDL_assert(stream->src_spec.freq == device->spec.freq);
SDL_assert(stream->dst_spec.format != SDL_AUDIO_UNKNOWN);
void *final_buf = output_buffer;
@@ -1391,6 +1397,7 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
typedef struct CountAudioDevicesData
{
int devs_seen;
int devs_skipped;
const int num_devices;
SDL_AudioDeviceID *result;
const bool recording;
@@ -1406,7 +1413,13 @@ static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table
const bool isphysical = !!(devid & (1<<1));
if (isphysical && (devid_recording == data->recording)) {
SDL_assert(data->devs_seen < data->num_devices);
data->result[data->devs_seen++] = devid;
SDL_AudioDevice *device = (SDL_AudioDevice *) value; // this is normally risky, but we hold the device_hash_lock here.
const bool zombie = SDL_GetAtomicInt(&device->zombie) != 0;
if (zombie) {
data->devs_skipped++;
} else {
data->result[data->devs_seen++] = devid;
}
}
return true; // keep iterating.
}
@@ -1422,10 +1435,11 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
num_devices = SDL_GetAtomicInt(recording ? &current_audio.recording_device_count : &current_audio.playback_device_count);
result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
if (result) {
CountAudioDevicesData data = { 0, num_devices, result, recording };
CountAudioDevicesData data = { 0, 0, num_devices, result, recording };
SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
SDL_assert(data.devs_seen == num_devices);
result[data.devs_seen] = 0; // null-terminated.
SDL_assert((data.devs_seen + data.devs_skipped) == num_devices);
num_devices = data.devs_seen; // might be less if we skipped any.
result[num_devices] = 0; // null-terminated.
}
}
SDL_UnlockRWLock(current_audio.device_hash_lock);
@@ -1567,7 +1581,9 @@ int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count)
SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
if (device) {
channels = device->spec.channels;
result = SDL_ChannelMapDup(device->chmap, channels);
if (channels > 0 && device->chmap) {
result = SDL_ChannelMapDup(device->chmap, channels);
}
}
ReleaseAudioDevice(device);
@@ -1965,10 +1981,6 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
} else if (logdev->simplified) {
result = SDL_SetError("Cannot change stream bindings on device opened with SDL_OpenAudioDeviceStream");
} else {
// !!! FIXME: We'll set the device's side's format below, but maybe we should refuse to bind a stream if the app's side doesn't have a format set yet.
// !!! FIXME: Actually, why do we allow there to be an invalid format, again?
// make sure start of list is sane.
SDL_assert(!logdev->bound_streams || (logdev->bound_streams->prev_binding == NULL));
@@ -2003,9 +2015,17 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
if (result) {
// Now that everything is verified, chain everything together.
const bool recording = device->recording;
for (int i = 0; i < num_streams; i++) {
SDL_AudioStream *stream = streams[i];
if (stream) { // shouldn't be NULL, but just in case...
// if the stream never had its non-device-end format set, just set it to the device end's format.
if (recording && (stream->dst_spec.format == SDL_AUDIO_UNKNOWN)) {
SDL_copyp(&stream->dst_spec, &device->spec);
} else if (!recording && (stream->src_spec.format == SDL_AUDIO_UNKNOWN)) {
SDL_copyp(&stream->src_spec, &device->spec);
}
stream->bound_device = logdev;
stream->prev_binding = NULL;
stream->next_binding = logdev->bound_streams;
+4
View File
@@ -537,8 +537,10 @@ static void SDL_TARGETING("ssse3") SDL_Convert_Swap32_SSSE3(Uint32* dst, const U
// behavior. However, the compiler support for this pragma is bad.
#if defined(__clang__)
#if __clang_major__ >= 12
#if defined(__aarch64__)
#pragma STDC FENV_ACCESS ON
#endif
#endif
#elif defined(_MSC_VER)
#pragma fenv_access (on)
#elif defined(__GNUC__)
@@ -814,8 +816,10 @@ static void SDL_Convert_Swap32_NEON(Uint32* dst, const Uint32* src, int num_samp
#if defined(__clang__)
#if __clang_major__ >= 12
#if defined(__aarch64__)
#pragma STDC FENV_ACCESS DEFAULT
#endif
#endif
#elif defined(_MSC_VER)
#pragma fenv_access (off)
#elif defined(__GNUC__)
+2 -2
View File
@@ -2114,8 +2114,8 @@ bool SDL_LoadWAV_IO(SDL_IOStream *src, bool closeio, SDL_AudioSpec *spec, Uint8
result = WaveLoad(src, &file, spec, audio_buf, audio_len);
if (!result) {
SDL_free(*audio_buf);
audio_buf = NULL;
audio_len = 0;
*audio_buf = NULL;
*audio_len = 0;
}
// Cleanup
+1 -1
View File
@@ -1156,7 +1156,7 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
#if SDL_ALSA_DEBUG
snd_pcm_uframes_t bufsize;
ALSA_snd_pcm_hw_params_get_buffer_size(cfg_ctx.hwparams, &bufsize);
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO,
"ALSA: period size = %ld, periods = %u, buffer size = %lu",
cfg_ctx.persize, cfg_ctx.periods, bufsize);
#endif
+1 -1
View File
@@ -206,7 +206,7 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
{
#ifdef HAVE_MMDEVICEAPI_H
if (SupportsIMMDevice) {
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN);
} else
#endif
{
+1 -1
View File
@@ -114,7 +114,7 @@ static bool PSPAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in
} else {
rc = sceAudioOutputPannedBlocking(device->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, (void *) buffer);
}
return (rc == 0);
return (rc >= 0);
}
static bool PSPAUDIO_WaitDevice(SDL_AudioDevice *device)
+1 -1
View File
@@ -337,7 +337,7 @@ typedef struct
static bool mgmtthrtask_DetectDevices(void *userdata)
{
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording);
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording, SDL_AUDIO_F32);
return true;
}
+1 -1
View File
@@ -814,7 +814,7 @@ static void ANDROIDCAMERA_Deinitialize(void)
static bool ANDROIDCAMERA_Init(SDL_CameraDriverImpl *impl)
{
// !!! FIXME: slide this off into a subroutine
// system libraries are in android-24 and later; we currently target android-16 and later, so check if they exist at runtime.
// system libraries are in android-24 and later; we currently target android-21 and later, so check if they exist at runtime.
void *libcamera2 = dlopen("libcamera2ndk.so", RTLD_NOW | RTLD_LOCAL);
if (!libcamera2) {
SDL_Log("CAMERA: libcamera2ndk.so can't be loaded: %s", dlerror());
+1 -1
View File
@@ -105,7 +105,7 @@ bool GDK_RegisterChangeNotifications(void)
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "[GDK] in RegisterAppConstrainedChangeNotification handler");
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this) {
if (constrained) {
if (constrained && !((_this->windows) && _this->windows->text_input_active)) {
SDL_SetKeyboardFocus(NULL);
} else {
SDL_SetKeyboardFocus(_this->windows);
+13 -9
View File
@@ -120,7 +120,7 @@ void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
}
}
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid)
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid, SDL_AudioFormat force_format)
{
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
@@ -162,7 +162,7 @@ static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devn
SDL_zero(spec);
spec.channels = (Uint8)fmt->Format.nChannels;
spec.freq = fmt->Format.nSamplesPerSec;
spec.format = SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
spec.format = (force_format != SDL_AUDIO_UNKNOWN) ? force_format : SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
if (!device) {
@@ -183,6 +183,7 @@ typedef struct SDLMMNotificationClient
{
const IMMNotificationClientVtbl *lpVtbl;
SDL_AtomicInt refcount;
SDL_AudioFormat force_format;
} SDLMMNotificationClient;
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_QueryInterface(IMMNotificationClient *client, REFIID iid, void **ppv)
@@ -241,6 +242,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceRemoved(IMMNoti
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *iclient, LPCWSTR pwstrDeviceId, DWORD dwNewState)
{
SDLMMNotificationClient *client = (SDLMMNotificationClient *)iclient;
IMMDevice *device = NULL;
if (SUCCEEDED(IMMDeviceEnumerator_GetDevice(enumerator, pwstrDeviceId, &device))) {
@@ -255,7 +257,7 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
GUID dsoundguid;
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
if (utf8dev) {
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid);
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid, client->force_format);
SDL_free(utf8dev);
}
} else {
@@ -286,7 +288,7 @@ static const IMMNotificationClientVtbl notification_client_vtbl = {
SDLMMNotificationClient_OnPropertyValueChanged
};
static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 } };
static SDLMMNotificationClient notification_client = { &notification_client_vtbl, { 1 }, SDL_AUDIO_UNKNOWN };
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
{
@@ -363,7 +365,7 @@ bool SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, bool reco
return true;
}
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device)
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device, SDL_AudioFormat force_format)
{
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
@@ -405,7 +407,7 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
SDL_zero(dsoundguid);
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
if (devname) {
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid);
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid, force_format);
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
*default_device = sdldevice;
}
@@ -422,10 +424,12 @@ static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **de
IMMDeviceCollection_Release(collection);
}
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording, SDL_AudioFormat force_format)
{
EnumerateEndpointsForFlow(false, default_playback);
EnumerateEndpointsForFlow(true, default_recording);
EnumerateEndpointsForFlow(false, default_playback, force_format);
EnumerateEndpointsForFlow(true, default_recording, force_format);
notification_client.force_format = force_format;
// if this fails, we just won't get hotplug events. Carry on anyhow.
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)&notification_client);
+1 -1
View File
@@ -37,7 +37,7 @@ typedef struct SDL_IMMDevice_callbacks
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
void SDL_IMMDevice_Quit(void);
bool SDL_IMMDevice_Get(struct SDL_AudioDevice *device, IMMDevice **immdevice, bool recording);
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording);
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording, SDL_AudioFormat force_format);
LPGUID SDL_IMMDevice_GetDirectSoundGUID(struct SDL_AudioDevice *device);
LPCWSTR SDL_IMMDevice_GetDevID(struct SDL_AudioDevice *device);
void SDL_IMMDevice_FreeDeviceHandle(struct SDL_AudioDevice *device);
+72
View File
@@ -53,6 +53,78 @@ typedef enum RO_INIT_TYPE
#define WC_ERR_INVALID_CHARS 0x00000080
#endif
// Fake window to help with DirectInput events.
HWND SDL_HelperWindow = NULL;
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
static const TCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
static ATOM SDL_HelperWindowClass = 0;
/*
* Creates a HelperWindow used for DirectInput.
*/
bool SDL_HelperWindowCreate(void)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASS wce;
// Make sure window isn't created twice.
if (SDL_HelperWindow != NULL) {
return true;
}
// Create the class.
SDL_zero(wce);
wce.lpfnWndProc = DefWindowProc;
wce.lpszClassName = SDL_HelperWindowClassName;
wce.hInstance = hInstance;
// Register the class.
SDL_HelperWindowClass = RegisterClass(&wce);
if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
return WIN_SetError("Unable to create Helper Window Class");
}
// Create the window.
SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
SDL_HelperWindowName,
WS_OVERLAPPED, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, HWND_MESSAGE, NULL,
hInstance, NULL);
if (!SDL_HelperWindow) {
UnregisterClass(SDL_HelperWindowClassName, hInstance);
return WIN_SetError("Unable to create Helper Window");
}
return true;
}
/*
* Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
*/
void SDL_HelperWindowDestroy(void)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
// Destroy the window.
if (SDL_HelperWindow != NULL) {
if (DestroyWindow(SDL_HelperWindow) == 0) {
WIN_SetError("Unable to destroy Helper Window");
return;
}
SDL_HelperWindow = NULL;
}
// Unregister the class.
if (SDL_HelperWindowClass != 0) {
if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
WIN_SetError("Unable to destroy Helper Window Class");
return;
}
SDL_HelperWindowClass = 0;
}
}
// Sets an error message based on an HRESULT
bool WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
{
+4 -4
View File
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,2,16,0
PRODUCTVERSION 3,2,16,0
FILEVERSION 3,2,20,0
PRODUCTVERSION 3,2,20,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "3, 2, 16, 0\0"
VALUE "FileVersion", "3, 2, 20, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL3.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "3, 2, 16, 0\0"
VALUE "ProductVersion", "3, 2, 20, 0\0"
END
END
BLOCK "VarFileInfo"
+7
View File
@@ -27,6 +27,8 @@
#import <Cocoa/Cocoa.h>
#import <UniformTypeIdentifiers/UTType.h>
extern void Cocoa_SetWindowHasModalDialog(SDL_Window *window, bool has_modal);
static void AddFileExtensionType(NSMutableArray *types, const char *pattern_ptr)
{
if (!*pattern_ptr) {
@@ -163,6 +165,9 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
if (window) {
w = (__bridge NSWindow *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
if (w) {
Cocoa_SetWindowHasModalDialog(window, true);
}
}
if (w) {
@@ -186,6 +191,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
callback(userdata, files, -1);
}
Cocoa_SetWindowHasModalDialog(window, false);
ReactivateAfterDialog();
}];
} else {
@@ -206,6 +212,7 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
const char *files[1] = { NULL };
callback(userdata, files, -1);
}
ReactivateAfterDialog();
}
}
+4 -4
View File
@@ -371,10 +371,10 @@ static const SDL_Scancode xfree86_scancode_table2[] = {
/* 188, 0x0bc */ SDL_SCANCODE_F18, // XF86Launch9
/* 189, 0x0bd */ SDL_SCANCODE_F19, // NoSymbol
/* 190, 0x0be */ SDL_SCANCODE_F20, // XF86AudioMicMute
/* 191, 0x0bf */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadToggle
/* 192, 0x0c0 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOn
/* 193, 0x0c1 */ SDL_SCANCODE_UNKNOWN, // XF86TouchpadOff
/* 194, 0x0c2 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
/* 191, 0x0bf */ SDL_SCANCODE_F21, // XF86TouchpadToggle
/* 192, 0x0c0 */ SDL_SCANCODE_F22, // XF86TouchpadOn
/* 193, 0x0c1 */ SDL_SCANCODE_F23, // XF86TouchpadOff
/* 194, 0x0c2 */ SDL_SCANCODE_F24, // NoSymbol
/* 195, 0x0c3 */ SDL_SCANCODE_MODE, // Mode_switch
/* 196, 0x0c4 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
/* 197, 0x0c5 */ SDL_SCANCODE_UNKNOWN, // NoSymbol
+5 -4
View File
@@ -1573,6 +1573,7 @@ SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
commandBufferHeader->copy_pass.in_progress = false;
commandBufferHeader->swapchain_texture_acquired = false;
commandBufferHeader->submitted = false;
commandBufferHeader->ignore_render_pass_texture_validation = false;
SDL_zeroa(commandBufferHeader->render_pass.vertex_sampler_bound);
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_texture_bound);
SDL_zeroa(commandBufferHeader->render_pass.vertex_storage_buffer_bound);
@@ -2247,14 +2248,14 @@ void SDL_DrawGPUIndexedPrimitivesIndirect(
void SDL_EndGPURenderPass(
SDL_GPURenderPass *render_pass)
{
CommandBufferCommonHeader *commandBufferCommonHeader;
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
if (render_pass == NULL) {
SDL_InvalidParamError("render_pass");
return;
}
CommandBufferCommonHeader *commandBufferCommonHeader;
commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
}
@@ -2543,7 +2544,7 @@ void SDL_EndGPUComputePass(
if (COMPUTEPASS_DEVICE->debug_mode) {
commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
commandBufferCommonHeader->compute_pass.in_progress = false;
commandBufferCommonHeader->compute_pass.compute_pipeline = false;
commandBufferCommonHeader->compute_pass.compute_pipeline = NULL;
SDL_zeroa(commandBufferCommonHeader->compute_pass.sampler_bound);
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_texture_bound);
SDL_zeroa(commandBufferCommonHeader->compute_pass.read_only_storage_buffer_bound);
+6 -5
View File
@@ -1194,7 +1194,6 @@ struct D3D12UniformBuffer
D3D12Buffer *buffer;
Uint32 writeOffset;
Uint32 drawOffset;
Uint32 currentBlockSize;
};
// Forward function declarations
@@ -1441,6 +1440,8 @@ static void D3D12_INTERNAL_ReleaseTextureContainer(
container->textures[i]);
}
SDL_DestroyProperties(container->header.info.props);
// Containers are just client handles, so we can destroy immediately
if (container->debugName) {
SDL_free(container->debugName);
@@ -4496,7 +4497,6 @@ static D3D12UniformBuffer *D3D12_INTERNAL_AcquireUniformBufferFromPool(
SDL_UnlockMutex(renderer->acquireUniformBufferLock);
uniformBuffer->currentBlockSize = 0;
uniformBuffer->drawOffset = 0;
uniformBuffer->writeOffset = 0;
@@ -4535,6 +4535,7 @@ static void D3D12_INTERNAL_PushUniformData(
Uint32 length)
{
D3D12UniformBuffer *uniformBuffer;
Uint32 blockSize;
if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) {
@@ -4559,13 +4560,13 @@ static void D3D12_INTERNAL_PushUniformData(
return;
}
uniformBuffer->currentBlockSize =
blockSize =
D3D12_INTERNAL_Align(
length,
256);
// If there is no more room, acquire a new uniform buffer
if (uniformBuffer->writeOffset + uniformBuffer->currentBlockSize >= UNIFORM_BUFFER_SIZE) {
if (uniformBuffer->writeOffset + blockSize >= UNIFORM_BUFFER_SIZE) {
ID3D12Resource_Unmap(
uniformBuffer->buffer->handle,
0,
@@ -4595,7 +4596,7 @@ static void D3D12_INTERNAL_PushUniformData(
data,
length);
uniformBuffer->writeOffset += uniformBuffer->currentBlockSize;
uniformBuffer->writeOffset += blockSize;
if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
commandBuffer->needVertexUniformBufferBind[slotIndex] = true;
+1
View File
@@ -888,6 +888,7 @@ static void METAL_INTERNAL_DestroyTextureContainer(
container->textures[i]->handle = nil;
SDL_free(container->textures[i]);
}
SDL_DestroyProperties(container->header.info.props);
if (container->debugName != NULL) {
SDL_free(container->debugName);
}
+36 -14
View File
@@ -1108,6 +1108,7 @@ typedef struct VulkanCommandBuffer
VulkanFenceHandle *inFlightFence;
bool autoReleaseFence;
bool swapchainRequested;
bool isDefrag; // Whether this CB was created for defragging
} VulkanCommandBuffer;
@@ -1277,13 +1278,20 @@ static inline const char *VkErrorMessages(VkResult code)
#undef ERR_TO_STR
}
#define SET_ERROR_AND_RETURN(fmt, msg, ret) \
#define SET_ERROR(fmt, msg) \
do { \
if (renderer->debugMode) { \
SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \
} \
SDL_SetError((fmt), (msg)); \
return ret; \
} while (0)
#define SET_STRING_ERROR(msg) SET_ERROR("%s", msg)
#define SET_ERROR_AND_RETURN(fmt, msg, ret) \
do { \
SET_ERROR(fmt, msg); \
return ret; \
} while (0)
#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret)
@@ -6951,6 +6959,8 @@ static void VULKAN_ReleaseTexture(
VULKAN_INTERNAL_ReleaseTexture(renderer, vulkanTextureContainer->textures[i]);
}
SDL_DestroyProperties(vulkanTextureContainer->header.info.props);
// Containers are just client handles, so we can destroy immediately
if (vulkanTextureContainer->debugName != NULL) {
SDL_free(vulkanTextureContainer->debugName);
@@ -8592,7 +8602,7 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets(
dynamicOffsetCount,
dynamicOffsets);
commandBuffer->needNewVertexUniformOffsets = false;
commandBuffer->needNewComputeUniformOffsets = false;
}
static void VULKAN_DispatchCompute(
@@ -9925,6 +9935,14 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false);
}
// The command buffer is flagged for cleanup when the swapchain is requested as a cleanup timing mechanism
vulkanCommandBuffer->swapchainRequested = true;
if (window->flags & SDL_WINDOW_HIDDEN) {
// Edge case, texture is filled in with NULL but not an error
return true;
}
// If window data marked as needing swapchain recreate, try to recreate
if (windowData->needsSwapchainRecreate) {
Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData);
@@ -9942,13 +9960,6 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
}
}
if (swapchainTextureWidth) {
*swapchainTextureWidth = windowData->width;
}
if (swapchainTextureHeight) {
*swapchainTextureHeight = windowData->height;
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (block) {
// If we are blocking, just wait for the fence!
@@ -10000,6 +10011,14 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
}
}
if (swapchainTextureWidth) {
*swapchainTextureWidth = windowData->width;
}
if (swapchainTextureHeight) {
*swapchainTextureHeight = windowData->height;
}
swapchainTextureContainer = &windowData->textureContainers[swapchainImageIndex];
// We need a special execution dependency with pWaitDstStageMask or image transition can start before acquire finishes
@@ -10377,6 +10396,7 @@ static void VULKAN_INTERNAL_CleanCommandBuffer(
commandBuffer->presentDataCount = 0;
commandBuffer->waitSemaphoreCount = 0;
commandBuffer->signalSemaphoreCount = 0;
commandBuffer->swapchainRequested = false;
// Reset defrag state
@@ -10533,7 +10553,7 @@ static bool VULKAN_Submit(
VulkanTextureSubresource *swapchainTextureSubresource;
VulkanMemorySubAllocator *allocator;
bool performCleanups =
(renderer->claimedWindowCount > 0 && vulkanCommandBuffer->presentDataCount > 0) ||
(renderer->claimedWindowCount > 0 && vulkanCommandBuffer->swapchainRequested) ||
renderer->claimedWindowCount == 0;
SDL_LockMutex(renderer->submitLock);
@@ -11686,7 +11706,7 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
if (!renderer) {
SDL_Vulkan_UnloadLibrary();
return false;
return NULL;
}
renderer->debugMode = debugMode;
@@ -11694,9 +11714,10 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
renderer->allowedFramesInFlight = 2;
if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
SET_STRING_ERROR("Failed to initialize Vulkan!");
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
SET_STRING_ERROR_AND_RETURN("Failed to initialize Vulkan!", NULL);
return NULL;
}
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan");
@@ -11722,9 +11743,10 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
if (!VULKAN_INTERNAL_CreateLogicalDevice(
renderer)) {
SET_STRING_ERROR("Failed to create logical device!");
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
SET_STRING_ERROR_AND_RETURN("Failed to create logical device!", NULL);
return NULL;
}
// FIXME: just move this into this function
-4
View File
@@ -31,11 +31,7 @@
/*
* External stuff.
*/
#ifdef SDL_VIDEO_DRIVER_WINDOWS
extern HWND SDL_HelperWindow;
#else
static const HWND SDL_HelperWindow = NULL;
#endif
/*
* Internal stuff.
+27 -1
View File
@@ -71,6 +71,11 @@ extern "C" {
#define DETACH_KERNEL_DRIVER
#endif
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:5287) /* operands are different enum types */
#endif
/* Uncomment to enable the retrieval of Usage and Usage Page in
hid_enumerate(). Warning, on platforms different from FreeBSD
this is very invasive as it requires the detach
@@ -918,6 +923,22 @@ static int should_enumerate_interface(unsigned short vendor_id, const struct lib
return 0;
}
static int libusb_blacklist(unsigned short vendor_id, unsigned short product_id)
{
size_t i;
static const struct { unsigned short vid; unsigned short pid; } known_bad[] = {
{ 0x1532, 0x0227 } /* Razer Huntsman Gaming keyboard - long delay asking for device details */
};
for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
return 1;
}
}
return 0;
}
struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
libusb_device **devs;
@@ -948,7 +969,8 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
unsigned short dev_pid = desc.idProduct;
if ((vendor_id != 0x0 && vendor_id != dev_vid) ||
(product_id != 0x0 && product_id != dev_pid)) {
(product_id != 0x0 && product_id != dev_pid) ||
libusb_blacklist(dev_vid, dev_pid)) {
continue;
}
@@ -2140,6 +2162,10 @@ uint16_t get_usb_code_for_current_locale(void)
return 0x0;
}
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
#ifdef __cplusplus
}
#endif
+1 -1
View File
@@ -134,7 +134,6 @@ static wchar_t *utf8_to_wchar_t(const char *utf8)
* Use register_error_str(NULL) to free the error message completely. */
static void register_error_str(wchar_t **error_str, const char *msg)
{
free(*error_str);
#ifdef HIDAPI_USING_SDL_RUNTIME
/* Thread-safe error handling */
if (msg) {
@@ -143,6 +142,7 @@ static void register_error_str(wchar_t **error_str, const char *msg)
SDL_ClearError();
}
#else
free(*error_str);
*error_str = utf8_to_wchar_t(msg);
#endif
}
+1
View File
@@ -949,6 +949,7 @@ static int hid_blacklist(unsigned short vendor_id, unsigned short product_id)
{ 0x0D8C, 0x0014 }, /* Sharkoon Skiller SGH2 headset - causes deadlock asking for device details */
{ 0x1532, 0x0109 }, /* Razer Lycosa Gaming keyboard - causes deadlock asking for device details */
{ 0x1532, 0x010B }, /* Razer Arctosa Gaming keyboard - causes deadlock asking for device details */
{ 0x1532, 0x0227 }, /* Razer Huntsman Gaming keyboard - long delay asking for device details */
{ 0x1B1C, 0x1B3D }, /* Corsair Gaming keyboard - causes deadlock asking for device details */
{ 0x1CCF, 0x0000 } /* All Konami Amusement Devices - causes deadlock asking for device details */
};
+7 -2
View File
@@ -311,7 +311,7 @@ void SDL_PrivateGamepadAdded(SDL_JoystickID instance_id)
{
SDL_Event event;
if (!SDL_gamepads_initialized) {
if (!SDL_gamepads_initialized || SDL_IsJoystickBeingAdded()) {
return;
}
@@ -913,7 +913,7 @@ static GamepadMapping_t *SDL_PrivateMatchGamepadMappingForGUID(SDL_GUID guid, bo
// An exact match, including CRC
return mapping;
} else if (crc && exact_match_crc) {
return NULL;
continue;
}
if (!best_match) {
@@ -1786,6 +1786,11 @@ static GamepadMapping_t *SDL_PrivateGenerateAutomaticGamepadMapping(const char *
char name_string[128];
char mapping[1024];
// Remove the CRC from the GUID
// We already know that this GUID doesn't have a mapping without the CRC, and we want newly
// added mappings without a CRC to override this mapping.
SDL_SetJoystickGUIDCRC(&guid, 0);
// Remove any commas in the name
SDL_strlcpy(name_string, name, sizeof(name_string));
{
+4 -2
View File
@@ -215,7 +215,7 @@ static const char *s_GamepadMappings[] = {
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,",
"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,rightx:a3,righty:a4,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,righttrigger:-a5,rightx:a3,righty:a4,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,",
@@ -416,12 +416,13 @@ static const char *s_GamepadMappings[] = {
"03000000790000004418000000010000,Mayflash 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,",
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
"03000000853200008906000000010000,NACON Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
"03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,rightx:a3,righty:a4,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,righttrigger:a5,rightx:a3,righty:a4,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,",
@@ -796,6 +797,7 @@ static const char *s_GamepadMappings[] = {
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000182e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+5 -1
View File
@@ -2143,6 +2143,7 @@ void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id)
SDL_JoystickDriver *driver;
int device_index;
int player_index = -1;
bool is_gamepad;
SDL_AssertJoysticksLocked();
@@ -2177,9 +2178,12 @@ void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id)
}
}
// This might create an automatic gamepad mapping, so wait to send the event
is_gamepad = SDL_IsGamepad(instance_id);
SDL_joystick_being_added = false;
if (SDL_IsGamepad(instance_id)) {
if (is_gamepad) {
SDL_PrivateGamepadAdded(instance_id);
}
}
+1 -1
View File
@@ -21,7 +21,6 @@
static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x0079, 0x181a ), k_eControllerType_PS3Controller, NULL }, // Venom Arcade Stick
{ MAKE_CONTROLLER_ID( 0x0079, 0x1844 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x044f, 0xb315 ), k_eControllerType_PS3Controller, NULL }, // Firestorm Dual Analog 3
{ MAKE_CONTROLLER_ID( 0x044f, 0xd007 ), k_eControllerType_PS3Controller, NULL }, // Thrustmaster wireless 3-1
{ MAKE_CONTROLLER_ID( 0x046d, 0xcad1 ), k_eControllerType_PS3Controller, NULL }, // Logitech Chillstream
@@ -96,6 +95,7 @@ static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef6 ), k_eControllerType_PS4Controller, NULL }, // Hitbox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1cf6 ), k_eControllerType_PS4Controller, NULL }, // EMIO PS4 Elite Controller
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1e10 ), k_eControllerType_PS4Controller, NULL }, // P4 Wired Gamepad generic knock off - lightbar but not trackpad or gyro
{ MAKE_CONTROLLER_ID( 0x0c12, 0x2e18 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0203 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS (PS4 peripheral but no trackpad/lightbar)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0207 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS V2 w/ Touchpad for PS4
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x020a ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS PS4/PS5 (PS4 mode)
+34 -1
View File
@@ -27,6 +27,7 @@
#include "SDL_iokitjoystick_c.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
#include "../../haptic/darwin/SDL_syshaptic_c.h" // For haptic hot plugging
#include "../usb_ids.h"
#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
@@ -213,6 +214,29 @@ static bool GetHIDScaledCalibratedState(recDevice *pDevice, recElement *pElement
return result;
}
static bool GetHIDScaledCalibratedState_NACON_Revolution_X_Unlimited(recDevice *pDevice, recElement *pElement, SInt32 min, SInt32 max, SInt32 *pValue)
{
if (pElement->minReport == 0 && pElement->maxReport == 255) {
return GetHIDScaledCalibratedState(pDevice, pElement, min, max, pValue);
}
// This device thumbstick axes have an unusual axis range that
// doesn't work with GetHIDScaledCalibratedState() above.
//
// See https://github.com/libsdl-org/SDL/issues/13143 for details
if (GetHIDElementState(pDevice, pElement, pValue)) {
if (*pValue >= 0) {
// Negative axis values range from 32767 (at rest) to 0 (minimum)
*pValue = -32767 + *pValue;
} else if (*pValue < 0) {
// Positive axis values range from -32768 (at rest) to 0 (maximum)
*pValue = 32768 + *pValue;
}
return true;
}
return false;
}
static void JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender)
{
recDevice *device = (recDevice *)ctx;
@@ -506,6 +530,11 @@ static bool GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
pDevice->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, (Uint16)vendor, (Uint16)product, (Uint16)version, manufacturer_string, product_string, 0, 0);
pDevice->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot((Uint16)vendor, (Uint16)product, product_string);
if (vendor == USB_VENDOR_NACON_ALT &&
product == USB_PRODUCT_NACON_REVOLUTION_X_UNLIMITED_BT) {
pDevice->nacon_revolution_x_unlimited = true;
}
array = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
if (array) {
AddHIDElements(array, pDevice);
@@ -957,7 +986,11 @@ static void DARWIN_JoystickUpdate(SDL_Joystick *joystick)
i = 0;
while (element) {
goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value);
if (device->nacon_revolution_x_unlimited) {
goodRead = GetHIDScaledCalibratedState_NACON_Revolution_X_Unlimited(device, element, -32768, 32767, &value);
} else {
goodRead = GetHIDScaledCalibratedState(device, element, -32768, 32767, &value);
}
if (goodRead) {
SDL_SendJoystickAxis(timestamp, joystick, i, value);
}
+1
View File
@@ -72,6 +72,7 @@ struct joystick_hwdata
int instance_id;
SDL_GUID guid;
int steam_virtual_gamepad_slot;
bool nacon_revolution_x_unlimited;
struct joystick_hwdata *pNext; // next device
};
+52 -54
View File
@@ -31,7 +31,9 @@
#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
// Define this if you want to log all packets from the controller
// #define DEBUG_GAMECUBE_PROTOCOL
#if 0
#define DEBUG_GAMECUBE_PROTOCOL
#endif
#define MAX_CONTROLLERS 4
@@ -119,22 +121,15 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
}
device->context = ctx;
ctx->joysticks[0] = 0;
ctx->joysticks[1] = 0;
ctx->joysticks[2] = 0;
ctx->joysticks[3] = 0;
ctx->rumble[0] = rumbleMagic;
ctx->useRumbleBrake = false;
if (device->vendor_id != USB_VENDOR_NINTENDO) {
ctx->pc_mode = true;
}
if (ctx->pc_mode) {
for (i = 0; i < MAX_CONTROLLERS; ++i) {
ResetAxisRange(ctx, i);
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
}
ResetAxisRange(ctx, 0);
HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
} else {
// This is all that's needed to initialize the device. Really!
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
@@ -204,69 +199,61 @@ static void HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device
{
}
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, int size)
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, bool invert_c_stick)
{
SDL_Joystick *joystick;
Uint8 i, v;
const Uint8 i = 0; // We have a separate context for each connected controller in PC mode, just use the first index
Uint8 v;
Sint16 axis_value;
Uint64 timestamp = SDL_GetTicksNS();
if (size != 10) {
return; // How do we handle this packet?
}
i = packet[0] - 1;
if (i >= MAX_CONTROLLERS) {
return; // How do we handle this packet?
}
joystick = SDL_GetJoystickFromID(ctx->joysticks[i]);
if (!joystick) {
// Hasn't been opened yet, skip
return;
}
#define READ_BUTTON(off, flag, button) \
SDL_SendJoystickButton( \
timestamp, \
joystick, \
button, \
#define READ_BUTTON(off, flag, button) \
SDL_SendJoystickButton( \
timestamp, \
joystick, \
button, \
((packet[off] & flag) != 0));
READ_BUTTON(1, 0x02, 0) // A
READ_BUTTON(1, 0x04, 1) // B
READ_BUTTON(1, 0x08, 3) // Y
READ_BUTTON(1, 0x01, 2) // X
READ_BUTTON(2, 0x80, 4) // DPAD_LEFT
READ_BUTTON(2, 0x20, 5) // DPAD_RIGHT
READ_BUTTON(2, 0x40, 6) // DPAD_DOWN
READ_BUTTON(2, 0x10, 7) // DPAD_UP
READ_BUTTON(2, 0x02, 8) // START
READ_BUTTON(1, 0x80, 9) // RIGHTSHOULDER
READ_BUTTON(0, 0x02, 0) // A
READ_BUTTON(0, 0x04, 1) // B
READ_BUTTON(0, 0x08, 3) // Y
READ_BUTTON(0, 0x01, 2) // X
READ_BUTTON(1, 0x80, 4) // DPAD_LEFT
READ_BUTTON(1, 0x20, 5) // DPAD_RIGHT
READ_BUTTON(1, 0x40, 6) // DPAD_DOWN
READ_BUTTON(1, 0x10, 7) // DPAD_UP
READ_BUTTON(1, 0x02, 8) // START
READ_BUTTON(0, 0x80, 9) // RIGHTSHOULDER
/* These two buttons are for the bottoms of the analog triggers.
* More than likely, you're going to want to read the axes instead!
* -flibit
*/
READ_BUTTON(1, 0x20, 10) // TRIGGERRIGHT
READ_BUTTON(1, 0x10, 11) // TRIGGERLEFT
READ_BUTTON(0, 0x20, 10) // TRIGGERRIGHT
READ_BUTTON(0, 0x10, 11) // TRIGGERLEFT
#undef READ_BUTTON
#define READ_AXIS(off, axis, invert) \
v = invert ? (0xff - packet[off]) : packet[off]; \
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
#define READ_AXIS(off, axis, invert) \
v = (invert) ? (0xff - packet[off]) : packet[off]; \
if (v < ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
if (v > ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis]) \
ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis] = v; \
axis_value = (Sint16)HIDAPI_RemapVal(v, ctx->min_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], ctx->max_axis[i * SDL_GAMEPAD_AXIS_COUNT + axis], SDL_MIN_SINT16, SDL_MAX_SINT16); \
SDL_SendJoystickAxis( \
timestamp, \
joystick, \
SDL_SendJoystickAxis( \
timestamp, \
joystick, \
axis, axis_value);
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTX, 0)
READ_AXIS(4, SDL_GAMEPAD_AXIS_LEFTY, 1)
READ_AXIS(6, SDL_GAMEPAD_AXIS_RIGHTX, 0)
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTY, 1)
READ_AXIS(7, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
READ_AXIS(8, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
READ_AXIS(2, SDL_GAMEPAD_AXIS_LEFTX, 0)
READ_AXIS(3, SDL_GAMEPAD_AXIS_LEFTY, 1)
READ_AXIS(5, SDL_GAMEPAD_AXIS_RIGHTX, invert_c_stick ? 1 : 0)
READ_AXIS(4, SDL_GAMEPAD_AXIS_RIGHTY, invert_c_stick ? 0 : 1)
READ_AXIS(6, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0)
READ_AXIS(7, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0)
#undef READ_AXIS
}
@@ -365,7 +352,18 @@ static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size);
#endif
if (ctx->pc_mode) {
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, size);
if (size == 10) {
// This is the older firmware
// The first byte is the index of the connected controller
// The C stick has an inverted value range compared to the left stick
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, &packet[1], true);
} else if (size == 9) {
// This is the newer firmware (version 0x7)
// The C stick has the same value range compared to the left stick
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, false);
} else {
// How do we handle this packet?
}
} else {
HIDAPI_DriverGameCube_HandleNintendoPacket(device, ctx, packet, size);
}
+2 -2
View File
@@ -1003,8 +1003,8 @@ static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet, int size)
{
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
static const float TOUCHPAD_SCALEY = 1.0f / 920; // This is noted as being 944 resolution, but 920 feels better
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
static const float TOUCHPAD_SCALEY = 1.08695652e-3f; // 1.0f / 920 // This is noted as being 944 resolution, but 920 feels better
Sint16 axis;
bool touchpad_down;
int touchpad_x, touchpad_y;
+14 -9
View File
@@ -812,14 +812,19 @@ static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx
}
if (ctx->sensors_supported) {
// Standard DualSense sensor update rate is 250 Hz over USB
float update_rate = 250.0f;
if (ctx->device->is_bluetooth) {
// Bluetooth sensor update rate appears to be 1000 Hz
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, 1000.0f);
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, 1000.0f);
} else {
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, 250.0f);
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, 250.0f);
update_rate = 1000.0f;
} else if (SDL_IsJoystickDualSenseEdge(ctx->device->vendor_id, ctx->device->product_id)) {
// DualSense Edge sensor update rate is 1000 Hz over USB
update_rate = 1000.0f;
}
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_GYRO, update_rate);
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
}
ctx->report_battery = true;
@@ -1355,8 +1360,8 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet, Uint64 timestamp)
{
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
bool touchpad_down;
int touchpad_x, touchpad_y;
@@ -1406,8 +1411,8 @@ static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet, Uint64 timestamp)
{
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
static const float TOUCHPAD_SCALEX = 5.20833333e-4f; // 1.0f / 1920
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
bool touchpad_down;
int touchpad_x, touchpad_y;
+72 -44
View File
@@ -58,9 +58,7 @@
#define SWITCH_GYRO_SCALE 14.2842f
#define SWITCH_ACCEL_SCALE 4096.f
#define SWITCH_GYRO_SCALE_OFFSET 13371.0f
#define SWITCH_GYRO_SCALE_MULT 936.0f
#define SWITCH_ACCEL_SCALE_OFFSET 16384.0f
#define SWITCH_ACCEL_SCALE_MULT 4.0f
enum
@@ -930,13 +928,14 @@ static bool SetIMUEnabled(SDL_DriverSwitch_Context *ctx, bool enabled)
static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
{
Uint8 *pLeftStickCal;
Uint8 *pRightStickCal;
Uint8 *pLeftStickCal = NULL;
Uint8 *pRightStickCal = NULL;
size_t stick, axis;
SwitchSubcommandInputPacket_t *user_reply = NULL;
SwitchSubcommandInputPacket_t *factory_reply = NULL;
SwitchSPIOpData_t readUserParams;
SwitchSPIOpData_t readFactoryParams;
Uint8 userParamsReadSuccessCount = 0;
// Read User Calibration Info
readUserParams.unAddress = k_unSPIStickUserCalibrationStartOffset;
@@ -949,33 +948,46 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset;
readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength;
const int MAX_ATTEMPTS = 3;
for (int attempt = 0; ; ++attempt) {
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) {
return false;
}
if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) {
// We successfully read the calibration data
break;
}
if (attempt == MAX_ATTEMPTS) {
return false;
}
}
// Automatically select the user calibration if magic bytes are set
if (user_reply && user_reply->stickUserCalibration.rgucLeftMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucLeftMagic[1] == 0xA1) {
userParamsReadSuccessCount += 1;
pLeftStickCal = user_reply->stickUserCalibration.rgucLeftCalibration;
} else {
pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration;
}
if (user_reply && user_reply->stickUserCalibration.rgucRightMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucRightMagic[1] == 0xA1) {
userParamsReadSuccessCount += 1;
pRightStickCal = user_reply->stickUserCalibration.rgucRightCalibration;
} else {
pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration;
}
// Only read the factory calibration info if we failed to receive the correct magic bytes
if (userParamsReadSuccessCount < 2) {
// Read Factory Calibration Info
readFactoryParams.unAddress = k_unSPIStickFactoryCalibrationStartOffset;
readFactoryParams.ucLength = k_unSPIStickFactoryCalibrationLength;
const int MAX_ATTEMPTS = 3;
for (int attempt = 0;; ++attempt) {
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readFactoryParams, sizeof(readFactoryParams), &factory_reply)) {
return false;
}
if (factory_reply->stickFactoryCalibration.opData.unAddress == k_unSPIStickFactoryCalibrationStartOffset) {
// We successfully read the calibration data
pLeftStickCal = factory_reply->stickFactoryCalibration.rgucLeftCalibration;
pRightStickCal = factory_reply->stickFactoryCalibration.rgucRightCalibration;
break;
}
if (attempt == MAX_ATTEMPTS) {
return false;
}
}
}
// If we still don't have calibration data, return false
if (pLeftStickCal == NULL || pRightStickCal == NULL)
{
return false;
}
/* Stick calibration values are 12-bits each and are packed by bit
@@ -1044,6 +1056,8 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
Uint8 *pIMUScale;
Sint16 sAccelRawX, sAccelRawY, sAccelRawZ, sGyroRawX, sGyroRawY, sGyroRawZ;
Sint16 sAccelSensCoeffX, sAccelSensCoeffY, sAccelSensCoeffZ;
Sint16 sGyroSensCoeffX, sGyroSensCoeffY, sGyroSensCoeffZ;
// IMU scale gives us multipliers for converting raw values to real world values
pIMUScale = reply->spiReadData.rgucReadData;
@@ -1052,10 +1066,18 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
sAccelRawY = (pIMUScale[3] << 8) | pIMUScale[2];
sAccelRawZ = (pIMUScale[5] << 8) | pIMUScale[4];
sAccelSensCoeffX = (pIMUScale[7] << 8) | pIMUScale[6];
sAccelSensCoeffY = (pIMUScale[9] << 8) | pIMUScale[8];
sAccelSensCoeffZ = (pIMUScale[11] << 8) | pIMUScale[10];
sGyroRawX = (pIMUScale[13] << 8) | pIMUScale[12];
sGyroRawY = (pIMUScale[15] << 8) | pIMUScale[14];
sGyroRawZ = (pIMUScale[17] << 8) | pIMUScale[16];
sGyroSensCoeffX = (pIMUScale[19] << 8) | pIMUScale[18];
sGyroSensCoeffY = (pIMUScale[21] << 8) | pIMUScale[20];
sGyroSensCoeffZ = (pIMUScale[23] << 8) | pIMUScale[22];
// Check for user calibration data. If it's present and set, it'll override the factory settings
readParams.unAddress = k_unSPIIMUUserScaleStartOffset;
readParams.ucLength = k_unSPIIMUUserScaleLength;
@@ -1072,14 +1094,14 @@ static bool LoadIMUCalibration(SDL_DriverSwitch_Context *ctx)
}
// Accelerometer scale
ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / (SWITCH_ACCEL_SCALE_OFFSET - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
ctx->m_IMUScaleData.fAccelScaleX = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffX - (float)sAccelRawX) * SDL_STANDARD_GRAVITY;
ctx->m_IMUScaleData.fAccelScaleY = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffY - (float)sAccelRawY) * SDL_STANDARD_GRAVITY;
ctx->m_IMUScaleData.fAccelScaleZ = SWITCH_ACCEL_SCALE_MULT / ((float)sAccelSensCoeffZ - (float)sAccelRawZ) * SDL_STANDARD_GRAVITY;
// Gyro scale
ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawX) * SDL_PI_F / 180.0f;
ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawY) * SDL_PI_F / 180.0f;
ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / (SWITCH_GYRO_SCALE_OFFSET - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
ctx->m_IMUScaleData.fGyroScaleX = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffX - (float)sGyroRawX) * SDL_PI_F / 180.0f;
ctx->m_IMUScaleData.fGyroScaleY = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffY - (float)sGyroRawY) * SDL_PI_F / 180.0f;
ctx->m_IMUScaleData.fGyroScaleZ = SWITCH_GYRO_SCALE_MULT / ((float)sGyroSensCoeffZ - (float)sGyroRawZ) * SDL_PI_F / 180.0f;
} else {
// Use default values
@@ -1101,14 +1123,17 @@ static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, i
{
sRawValue -= ctx->m_StickCalData[nStick].axis[nAxis].sCenter;
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
if (sRawValue >= 0) {
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
} else {
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
}
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, ctx->m_StickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
}
static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
@@ -1118,14 +1143,17 @@ static Sint16 ApplySimpleStickCalibration(SDL_DriverSwitch_Context *ctx, int nSt
sRawValue -= usJoystickCenter;
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
if (sRawValue >= 0) {
if (sRawValue > ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
} else {
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
}
if (sRawValue < ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin) {
ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin = sRawValue;
}
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMin, ctx->m_SimpleStickExtents[nStick].axis[nAxis].sMax, SDL_MIN_SINT16, SDL_MAX_SINT16);
}
static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
+1
View File
@@ -84,6 +84,7 @@
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRED 0x0d17
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS 0x0d18
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRED 0x0d19
#define USB_PRODUCT_NACON_REVOLUTION_X_UNLIMITED_BT 0x0689
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
#define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019
#define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e
-4
View File
@@ -40,11 +40,7 @@
#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF)
// external variables referenced.
#ifdef SDL_VIDEO_DRIVER_WINDOWS
extern HWND SDL_HelperWindow;
#else
static const HWND SDL_HelperWindow = NULL;
#endif
// local variables
static bool coinitialized = false;
+5 -3
View File
@@ -2685,6 +2685,8 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer)
view->pixel_h = (int) view->logical_dst_rect.h;
UpdatePixelViewport(renderer, view);
UpdatePixelClipRect(renderer, view);
QueueCmdSetViewport(renderer);
QueueCmdSetClipRect(renderer);
}
bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode)
@@ -3605,7 +3607,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
#endif
SDL_RenderViewState *view = renderer->view;
const bool islogical = ((view == &renderer->main_view) && (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED));
const bool islogical = (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED);
if (islogical || (renderer->line_method == SDL_RENDERLINEMETHOD_GEOMETRY)) {
const float scale_x = view->current_scale.x;
@@ -3624,7 +3626,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
int num_indices = 0;
const int size_indices = 4;
int cur_index = -4;
const int is_looping = (points[0].x == points[count - 1].x && points[0].y == points[count - 1].y);
const bool is_looping = (points[0].x == points[count - 1].x && points[0].y == points[count - 1].y);
SDL_FPoint p; // previous point
p.x = p.y = 0.0f;
/* p q
@@ -3656,7 +3658,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count
num_indices += 3;
// closed polyline, don´t draw twice the point
if (i || is_looping == 0) {
if (i || !is_looping) {
ADD_TRIANGLE(4, 5, 6)
ADD_TRIANGLE(4, 6, 7)
}
+16
View File
@@ -1651,6 +1651,8 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
} else {
renderdata->glGenTextures(1, &data->texture_v);
if (!GL_CheckError("glGenTexures()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
}
@@ -1665,6 +1667,8 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
} else {
renderdata->glGenTextures(1, &data->texture_u);
if (!GL_CheckError("glGenTexures()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
}
@@ -1672,11 +1676,15 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
renderdata->glBindTexture(data->texture_type, data->texture_u);
renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
if (!GL_CheckError("glTexImage2D()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_U_NUMBER, data->texture_u);
if (!SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8)) {
SDL_free(data->pixel_data);
SDL_free(data);
return SDL_SetError("Unsupported YUV colorspace");
}
} else if (data->nv12) {
@@ -1686,6 +1694,8 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
} else {
renderdata->glGenTextures(1, &data->texture_u);
if (!GL_CheckError("glGenTexures()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
}
@@ -1693,11 +1703,15 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
renderdata->glBindTexture(data->texture_type, data->texture_u);
renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
if (!GL_CheckError("glTexImage2D()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_UV_NUMBER, data->texture_u);
if (!SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8)) {
SDL_free(data->pixel_data);
SDL_free(data);
return SDL_SetError("Unsupported YUV colorspace");
}
}
@@ -1709,6 +1723,8 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
} else {
renderdata->glGenTextures(1, &data->texture);
if (!GL_CheckError("glGenTexures()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
}
+2 -2
View File
@@ -3763,7 +3763,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
VULKAN_SetupShaderConstants(renderer, cmd, texture, &constants);
switch (cmd->data.draw.texture_scale_mode) {
case VK_FILTER_NEAREST:
case SDL_SCALEMODE_NEAREST:
switch (cmd->data.draw.texture_address_mode) {
case SDL_TEXTURE_ADDRESS_CLAMP:
textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_CLAMP];
@@ -3775,7 +3775,7 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
}
break;
case VK_FILTER_LINEAR:
case SDL_SCALEMODE_LINEAR:
switch (cmd->data.draw.texture_address_mode) {
case SDL_TEXTURE_ADDRESS_CLAMP:
textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_CLAMP];
+6 -1
View File
@@ -41,7 +41,12 @@
#define environ (*_NSGetEnviron())
#elif defined(SDL_PLATFORM_FREEBSD)
#include <dlfcn.h>
#define environ ((char **)dlsym(RTLD_DEFAULT, "environ"))
static char **get_environ_rtld(void)
{
char ***environ_rtld = (char ***)dlsym(RTLD_DEFAULT, "environ");
return environ_rtld ? *environ_rtld : NULL;
}
#define environ (get_environ_rtld())
#else
extern char **environ;
#endif
+7
View File
@@ -1478,6 +1478,13 @@ DLMALLOC_EXPORT int mspace_mallopt(int, int);
#endif /* NO_MALLOC_STATS */
#ifndef LACKS_ERRNO_H
#include <errno.h> /* for MALLOC_FAILURE_ACTION */
#else /* LACKS_ERRNO_H */
#ifndef EINVAL
#define EINVAL 22
#endif
#ifndef ENOMEM
#define ENOMEM 12
#endif
#endif /* LACKS_ERRNO_H */
#ifdef DEBUG
#if ABORT_ON_ASSERT_FAILURE
+9 -1
View File
@@ -32,6 +32,8 @@
#include <pspkerneltypes.h>
#include <pspthreadman.h>
#define PSP_THREAD_NAME_MAX 32
static int ThreadEntry(SceSize args, void *argp)
{
SDL_RunThread(*(SDL_Thread **)argp);
@@ -44,6 +46,7 @@ bool SDL_SYS_CreateThread(SDL_Thread *thread,
{
SceKernelThreadInfo status;
int priority = 32;
char thread_name[PSP_THREAD_NAME_MAX];
// Set priority of new thread to the same as the current thread
status.size = sizeof(SceKernelThreadInfo);
@@ -51,7 +54,12 @@ bool SDL_SYS_CreateThread(SDL_Thread *thread,
priority = status.currentPriority;
}
thread->handle = sceKernelCreateThread(thread->name, ThreadEntry,
SDL_strlcpy(thread_name, "SDL thread", PSP_THREAD_NAME_MAX);
if (thread->name) {
SDL_strlcpy(thread_name, thread->name, PSP_THREAD_NAME_MAX);
}
thread->handle = sceKernelCreateThread(thread_name, ThreadEntry,
priority, thread->stacksize ? ((int)thread->stacksize) : 0x8000,
PSP_THREAD_ATTR_VFPU, NULL);
if (thread->handle < 0) {
+10 -4
View File
@@ -42,6 +42,10 @@ void SDL_CancelClipboardData(Uint32 sequence)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this) {
return;
}
if (sequence && sequence != _this->clipboard_sequence) {
// This clipboard data was already canceled
return;
@@ -62,6 +66,10 @@ bool SDL_SaveClipboardMimeTypes(const char **mime_types, size_t num_mime_types)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this) {
return SDL_UninitializedVideo();
}
SDL_FreeClipboardMimeTypes(_this);
if (mime_types && num_mime_types > 0) {
@@ -234,13 +242,11 @@ bool SDL_HasClipboardData(const char *mime_type)
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (!_this) {
SDL_UninitializedVideo();
return false;
return SDL_UninitializedVideo();
}
if (!mime_type) {
SDL_InvalidParamError("mime_type");
return false;
return SDL_InvalidParamError("mime_type");
}
if (_this->HasClipboardData) {
+1 -1
View File
@@ -1247,7 +1247,7 @@ bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surfac
// Clip again
SDL_GetRectIntersection(clip_rect, &final_dst, &final_dst);
if (final_dst.w == 0 || final_dst.h == 0 ||
if (final_dst.w <= 0 || final_dst.h <= 0 ||
final_src.w < 0 || final_src.h < 0) {
// No-op.
return true;
+6
View File
@@ -103,6 +103,7 @@ struct SDL_Window
bool restore_on_show; // Child was hidden recursively by the parent, restore when shown.
bool last_position_pending; // This should NOT be cleared by the backend, as it is used for fullscreen positioning.
bool last_size_pending; // This should be cleared by the backend if the new size cannot be applied.
bool constrain_popup;
bool is_destroying;
bool is_dropping; // drag/drop in progress, expecting SDL_SendDropComplete().
@@ -129,6 +130,9 @@ struct SDL_Window
SDL_WindowData *internal;
// If a toplevel window, holds the current keyboard focus for grabbing popups.
SDL_Window *keyboard_focus;
SDL_Window *prev;
SDL_Window *next;
@@ -565,6 +569,8 @@ extern bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags);
extern bool SDL_HasWindows(void);
extern void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel_y, int *abs_x, int *abs_y);
extern void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int *rel_x, int *rel_y);
extern bool SDL_ShouldFocusPopup(SDL_Window *window);
extern bool SDL_ShouldRelinquishPopupFocus(SDL_Window *window, SDL_Window **new_focus);
extern void SDL_OnDisplayAdded(SDL_VideoDisplay *display);
extern void SDL_OnDisplayMoved(SDL_VideoDisplay *display);
+52 -2
View File
@@ -171,9 +171,10 @@ static VideoBootStrap *bootstrap[] = {
}
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA)
// Support for macOS fullscreen spaces
// Support for macOS fullscreen spaces, etc.
extern bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window);
extern bool Cocoa_SetWindowFullscreenSpace(SDL_Window *window, bool state, bool blocking);
extern bool Cocoa_IsShowingModalDialog(SDL_Window *window);
#endif
#ifdef SDL_VIDEO_DRIVER_UIKIT
@@ -2503,6 +2504,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
window->is_destroying = false;
window->last_displayID = SDL_GetDisplayForWindow(window);
window->external_graphics_context = external_graphics_context;
window->constrain_popup = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN, true);
if (_this->windows) {
_this->windows->prev = window;
@@ -3661,6 +3663,10 @@ bool SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent)
CHECK_WINDOW_NOT_POPUP(parent, false);
}
if (window == parent) {
return SDL_SetError("Cannot set the parent of a window to itself.");
}
if (!_this->SetWindowParent) {
return SDL_Unsupported();
}
@@ -3706,6 +3712,48 @@ bool SDL_SetWindowModal(SDL_Window *window, bool modal)
return _this->SetWindowModal(_this, window, modal);
}
bool SDL_ShouldRelinquishPopupFocus(SDL_Window *window, SDL_Window **new_focus)
{
SDL_Window *focus = window->parent;
bool set_focus = !!(window->flags & SDL_WINDOW_INPUT_FOCUS);
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed, and can grab the keyboard focus.
while (SDL_WINDOW_IS_POPUP(focus) && ((focus->flags & SDL_WINDOW_NOT_FOCUSABLE) || focus->is_hiding || focus->is_destroying)) {
focus = focus->parent;
// If some window in the chain currently had focus, set it to the new lowest-level window.
if (!set_focus) {
set_focus = !!(focus->flags & SDL_WINDOW_INPUT_FOCUS);
}
}
*new_focus = focus;
return set_focus;
}
bool SDL_ShouldFocusPopup(SDL_Window *window)
{
SDL_Window *toplevel_parent;
for (toplevel_parent = window->parent; SDL_WINDOW_IS_POPUP(toplevel_parent); toplevel_parent = toplevel_parent->parent) {
}
SDL_Window *current_focus = toplevel_parent->keyboard_focus;
bool found_higher_focus = false;
/* Traverse the window tree from the currently focused window to the toplevel parent and see if we encounter
* the new focus request. If the new window is found, a higher-level window already has focus.
*/
SDL_Window *w;
for (w = current_focus; w != toplevel_parent; w = w->parent) {
if (w == window) {
found_higher_focus = true;
break;
}
}
return !found_higher_focus || w == toplevel_parent;
}
bool SDL_SetWindowFocusable(SDL_Window *window, bool focusable)
{
CHECK_WINDOW_MAGIC(window, false);
@@ -4124,7 +4172,9 @@ static bool SDL_ShouldMinimizeOnFocusLoss(SDL_Window *window)
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA)
if (SDL_strcmp(_this->name, "cocoa") == 0) { // don't do this for X11, etc
if (Cocoa_IsWindowInFullscreenSpace(window)) {
if (Cocoa_IsShowingModalDialog(window)) {
return false; // modal system dialogs can live over fullscreen windows, don't minimize.
} else if (Cocoa_IsWindowInFullscreenSpace(window)) {
return false;
}
}
+14 -3
View File
@@ -311,15 +311,26 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
if (!SDL_GetHintBoolean("SDL_MAC_REGISTER_ACTIVATION_HANDLERS", true))
if (!SDL_GetHintBoolean("SDL_MAC_REGISTER_ACTIVATION_HANDLERS", true)) {
return;
}
/* The menu bar of SDL apps which don't have the typical .app bundle
* structure fails to work the first time a window is created (until it's
* de-focused and re-focused), if this call is in Cocoa_RegisterApp instead
* of here. https://bugzilla.libsdl.org/show_bug.cgi?id=3051
* of here. https://github.com/libsdl-org/SDL/issues/1913
*/
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, false)) {
/* this apparently became unnecessary on macOS 14.0, and will addition pop up a
hidden dock if you're moving the mouse during launch, so change the default
behaviour there. https://github.com/libsdl-org/SDL/issues/10340
(13.6 still needs it, presumably 13.7 does, too.) */
bool background_app_default = false;
if (@available(macOS 14.0, *)) {
background_app_default = true; /* by default, don't explicitly activate the dock and then us again to force to foreground */
}
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, background_app_default)) {
// Get more aggressive for Catalina: activate the Dock first so we definitely reset all activation state.
for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
[i activateWithOptions:NSApplicationActivateIgnoringOtherApps];
+1 -1
View File
@@ -146,13 +146,13 @@ typedef enum
@property(nonatomic) BOOL was_zoomed;
@property(nonatomic) NSInteger window_number;
@property(nonatomic) NSInteger flash_request;
@property(nonatomic) SDL_Window *keyboard_focus;
@property(nonatomic) SDL3Cocoa_WindowListener *listener;
@property(nonatomic) NSModalSession modal_session;
@property(nonatomic) SDL_CocoaVideoData *videodata;
@property(nonatomic) bool pending_size;
@property(nonatomic) bool pending_position;
@property(nonatomic) bool border_toggled;
@property(nonatomic) bool has_modal_dialog;
#ifdef SDL_VIDEO_OPENGL_EGL
@property(nonatomic) EGLSurface egl_surface;
+61 -40
View File
@@ -432,6 +432,18 @@ bool Cocoa_IsWindowZoomed(SDL_Window *window)
return zoomed;
}
bool Cocoa_IsShowingModalDialog(SDL_Window *window)
{
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
return data.has_modal_dialog;
}
void Cocoa_SetWindowHasModalDialog(SDL_Window *window, bool has_modal)
{
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
data.has_modal_dialog = has_modal;
}
typedef enum CocoaMenuVisibility
{
COCOA_MENU_VISIBILITY_AUTO = 0,
@@ -707,10 +719,7 @@ static SDL_Window *GetParentToplevelWindow(SDL_Window *window)
static void Cocoa_SetKeyboardFocus(SDL_Window *window, bool set_active_focus)
{
SDL_Window *toplevel = GetParentToplevelWindow(window);
SDL_CocoaWindowData *toplevel_data;
toplevel_data = (__bridge SDL_CocoaWindowData *)toplevel->internal;
toplevel_data.keyboard_focus = window;
toplevel->keyboard_focus = window;
if (set_active_focus && !window->is_hiding && !window->is_destroying) {
SDL_SetKeyboardFocus(window);
@@ -1190,21 +1199,27 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
ScheduleContextUpdates(_data);
/* isZoomed always returns true if the window is not resizable
* and fullscreen windows are considered zoomed.
/* The OS can resize the window automatically if the display density
* changes while the window is miniaturized or hidden.
*/
if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed] &&
!(window->flags & SDL_WINDOW_FULLSCREEN) && ![self isInFullscreenSpace]) {
zoomed = YES;
} else {
zoomed = NO;
}
if (!zoomed) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
} else {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0);
if ([self windowOperationIsPending:PENDING_OPERATION_MINIMIZE]) {
[nswindow miniaturize:nil];
if ([nswindow isVisible])
{
/* isZoomed always returns true if the window is not resizable
* and fullscreen windows are considered zoomed.
*/
if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed] &&
!(window->flags & SDL_WINDOW_FULLSCREEN) && ![self isInFullscreenSpace]) {
zoomed = YES;
} else {
zoomed = NO;
}
if (!zoomed) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
} else {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0);
if ([self windowOperationIsPending:PENDING_OPERATION_MINIMIZE]) {
[nswindow miniaturize:nil];
}
}
}
@@ -1252,7 +1267,7 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
// We're going to get keyboard events, since we're key.
// This needs to be done before restoring the relative mouse mode.
Cocoa_SetKeyboardFocus(_data.keyboard_focus ? _data.keyboard_focus : window, true);
Cocoa_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window, true);
// If we just gained focus we need the updated mouse position
if (!(window->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE)) {
@@ -2261,7 +2276,9 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
[nswindow setIgnoresMouseEvents:YES];
[nswindow setAcceptsMouseMovedEvents:NO];
} else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_HIDDEN)) {
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
if (!(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
Cocoa_SetKeyboardFocus(window, true);
}
Cocoa_UpdateMouseFocus();
}
}
@@ -2351,7 +2368,7 @@ bool Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
rect.origin.y -= screenRect.origin.y;
// Constrain the popup
if (SDL_WINDOW_IS_POPUP(window)) {
if (SDL_WINDOW_IS_POPUP(window) && window->constrain_popup) {
if (rect.origin.x + rect.size.width > screenRect.origin.x + screenRect.size.width) {
rect.origin.x -= (rect.origin.x + rect.size.width) - (screenRect.origin.x + screenRect.size.width);
}
@@ -2507,7 +2524,7 @@ bool Cocoa_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
ConvertNSRect(&rect);
// Position and constrain the popup
if (SDL_WINDOW_IS_POPUP(window)) {
if (SDL_WINDOW_IS_POPUP(window) && window->constrain_popup) {
NSRect screenRect = [ScreenForRect(&rect) frame];
if (rect.origin.x + rect.size.width > screenRect.origin.x + screenRect.size.width) {
@@ -2648,7 +2665,9 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
}
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
if (!(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
Cocoa_SetKeyboardFocus(window, true);
}
Cocoa_UpdateMouseFocus();
}
}
@@ -2682,20 +2701,9 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
Cocoa_SetWindowModal(_this, window, false);
// Transfer keyboard focus back to the parent when closing a popup menu
if (window->flags & SDL_WINDOW_POPUP_MENU) {
SDL_Window *new_focus = window->parent;
bool set_focus = window == SDL_GetKeyboardFocus();
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed.
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
new_focus = new_focus->parent;
// If some window in the chain currently had focus, set it to the new lowest-level window.
if (!set_focus) {
set_focus = new_focus == SDL_GetKeyboardFocus();
}
}
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
Cocoa_SetKeyboardFocus(new_focus, set_focus);
Cocoa_UpdateMouseFocus();
} else if (window->parent && waskey) {
@@ -3122,20 +3130,19 @@ void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
#endif // SDL_VIDEO_OPENGL
SDL_Window *topmost = GetParentToplevelWindow(window);
SDL_CocoaWindowData *topmost_data = (__bridge SDL_CocoaWindowData *)topmost->internal;
/* Reset the input focus of the root window if this window is still set as keyboard focus.
* SDL_DestroyWindow will have already taken care of reassigning focus if this is the SDL
* keyboard focus, this ensures that an inactive window with this window set as input focus
* does not try to reference it the next time it gains focus.
*/
if (topmost_data.keyboard_focus == window) {
if (topmost->keyboard_focus == window) {
SDL_Window *new_focus = window;
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
new_focus = new_focus->parent;
}
topmost_data.keyboard_focus = new_focus;
topmost->keyboard_focus = new_focus;
}
if ([data.listener isInFullscreenSpace]) {
@@ -3300,6 +3307,20 @@ bool Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOper
bool Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable)
{
if (window->flags & SDL_WINDOW_POPUP_MENU) {
if (!(window->flags & SDL_WINDOW_HIDDEN)) {
if (!focusable && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
Cocoa_SetKeyboardFocus(new_focus, set_focus);
} else if (focusable) {
if (SDL_ShouldFocusPopup(window)) {
Cocoa_SetKeyboardFocus(window, true);
}
}
}
}
return true; // just succeed, the real work is done elsewhere.
}
+1 -1
View File
@@ -1717,7 +1717,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
window->keyboard_device = input;
// Restore the keyboard focus to the child popup that was holding it
SDL_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window->sdlwindow);
SDL_SetKeyboardFocus(window->sdlwindow->keyboard_focus ? window->sdlwindow->keyboard_focus : window->sdlwindow);
#ifdef SDL_USE_IME
if (!input->text_input) {
+1
View File
@@ -642,6 +642,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
device->SyncWindow = Wayland_SyncWindow;
device->SetWindowFocusable = Wayland_SetWindowFocusable;
#ifdef SDL_USE_LIBDBUS
if (SDL_SystemTheme_Init())
+66 -65
View File
@@ -181,7 +181,7 @@ static void SetMinMaxDimensions(SDL_Window *window)
#ifdef HAVE_LIBDECOR_H
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
if (!wind->shell_surface.libdecor.initial_configure_seen || !wind->shell_surface.libdecor.frame) {
if (!wind->shell_surface.libdecor.frame) {
return; // Can't do anything yet, wait for ShowWindow
}
/* No need to change these values if the window is non-resizable,
@@ -198,7 +198,7 @@ static void SetMinMaxDimensions(SDL_Window *window)
} else
#endif
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) {
if (!wind->shell_surface.xdg.toplevel.xdg_toplevel) {
return; // Can't do anything yet, wait for ShowWindow
}
xdg_toplevel_set_min_size(wind->shell_surface.xdg.toplevel.xdg_toplevel,
@@ -215,32 +215,32 @@ static void EnsurePopupPositionIsValid(SDL_Window *window, int *x, int *y)
int adj_count = 0;
/* Per the xdg-positioner spec, child popup windows must intersect or at
* least be partially adjacent to the parent window.
* least be partially adjoining the parent window.
*
* Failure to ensure this on a compositor that enforces this restriction
* can result in behavior ranging from the window being spuriously closed
* to a protocol violation.
*/
if (*x + window->w < 0) {
if (*x + window->w <= 0) {
*x = -window->w;
++adj_count;
}
if (*y + window->h < 0) {
if (*y + window->h <= 0) {
*y = -window->h;
++adj_count;
}
if (*x > window->parent->w) {
if (*x >= window->parent->w) {
*x = window->parent->w;
++adj_count;
}
if (*y > window->parent->h) {
if (*y >= window->parent->h) {
*y = window->parent->h;
++adj_count;
}
/* If adjustment was required on the x and y axes, the popup is aligned with
* the parent corner-to-corner and is neither overlapping nor adjacent, so it
* must be nudged by 1 to be considered adjacent.
* the parent corner-to-corner and is neither overlapping nor adjoining, so it
* must be nudged by 1 to be considered adjoining.
*/
if (adj_count > 1) {
*x += *x < 0 ? 1 : -1;
@@ -753,7 +753,9 @@ static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *x
xdg_surface_ack_configure(xdg, serial);
}
wind->shell_surface.xdg.initial_configure_seen = true;
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
}
}
static const struct xdg_surface_listener shell_surface_listener_xdg = {
@@ -970,10 +972,6 @@ static void handle_configure_xdg_toplevel(void *data,
wind->active = active;
window->tiled = tiled;
wind->resizing = resizing;
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
}
}
static void handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
@@ -1122,9 +1120,7 @@ static void handle_configure_zxdg_decoration(void *data,
WAYLAND_wl_display_roundtrip(internal->waylandData->display);
Wayland_HideWindow(device, window);
SDL_zero(internal->shell_surface);
internal->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR;
Wayland_ShowWindow(device, window);
}
}
@@ -1406,11 +1402,8 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
libdecor_state_free(state);
}
if (!wind->shell_surface.libdecor.initial_configure_seen) {
LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height);
wind->shell_surface.libdecor.initial_configure_seen = true;
}
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height);
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME;
}
@@ -1666,7 +1659,7 @@ static const struct wp_color_management_surface_feedback_v1_listener color_manag
feedback_surface_preferred_changed
};
static void SetKeyboardFocus(SDL_Window *window, bool set_focus)
static void Wayland_SetKeyboardFocus(SDL_Window *window, bool set_focus)
{
SDL_Window *toplevel = window;
@@ -1675,7 +1668,7 @@ static void SetKeyboardFocus(SDL_Window *window, bool set_focus)
toplevel = toplevel->parent;
}
toplevel->internal->keyboard_focus = window;
toplevel->keyboard_focus = window;
if (set_focus && !window->is_hiding && !window->is_destroying) {
SDL_SetKeyboardFocus(window);
@@ -1819,12 +1812,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
}
/* The window was hidden, but the sync point hasn't yet been reached.
* Pump events to avoid a possible protocol violation.
*/
if (data->show_hide_sync_required) {
// Always roundtrip to ensure there are no pending buffer attachments.
do {
WAYLAND_wl_display_roundtrip(c->display);
}
} while (data->show_hide_sync_required);
data->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE;
@@ -1905,8 +1896,9 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
data->shell_surface.xdg.popup.xdg_positioner = xdg_wm_base_create_positioner(c->shell.xdg);
xdg_positioner_set_anchor(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT);
xdg_positioner_set_anchor_rect(data->shell_surface.xdg.popup.xdg_positioner, 0, 0, parent->internal->current.logical_width, parent->internal->current.logical_width);
xdg_positioner_set_constraint_adjustment(data->shell_surface.xdg.popup.xdg_positioner,
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
const Uint32 constraint = window->constrain_popup ? (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) : XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE;
xdg_positioner_set_constraint_adjustment(data->shell_surface.xdg.popup.xdg_positioner, constraint);
xdg_positioner_set_gravity(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
xdg_positioner_set_size(data->shell_surface.xdg.popup.xdg_positioner, data->current.logical_width, data->current.logical_height);
@@ -1935,8 +1927,8 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
wl_region_add(region, 0, 0, 0, 0);
wl_surface_set_input_region(data->surface, region);
wl_region_destroy(region);
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
} else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
Wayland_SetKeyboardFocus(window, true);
}
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER, data->shell_surface.xdg.popup.xdg_popup);
@@ -1984,7 +1976,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
#ifdef HAVE_LIBDECOR_H
if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
if (data->shell_surface.libdecor.frame) {
while (!data->shell_surface.libdecor.initial_configure_seen) {
while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
WAYLAND_wl_display_flush(c->display);
WAYLAND_wl_display_dispatch(c->display);
}
@@ -1998,7 +1990,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
*/
wl_surface_commit(data->surface);
if (data->shell_surface.xdg.surface) {
while (!data->shell_surface.xdg.initial_configure_seen) {
while (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
WAYLAND_wl_display_flush(c->display);
WAYLAND_wl_display_dispatch(c->display);
}
@@ -2083,21 +2075,10 @@ static void Wayland_ReleasePopup(SDL_VideoDevice *_this, SDL_Window *popup)
return;
}
if (popup->flags & SDL_WINDOW_POPUP_MENU) {
SDL_Window *new_focus = popup->parent;
bool set_focus = popup == SDL_GetKeyboardFocus();
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed.
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
new_focus = new_focus->parent;
// If some window in the chain currently had focus, set it to the new lowest-level window.
if (!set_focus) {
set_focus = new_focus == SDL_GetKeyboardFocus();
}
}
SetKeyboardFocus(new_focus, set_focus);
if ((popup->flags & SDL_WINDOW_POPUP_MENU) && !(popup->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(popup, &new_focus);
Wayland_SetKeyboardFocus(new_focus, set_focus);
}
xdg_popup_destroy(popupdata->shell_surface.xdg.popup.xdg_popup);
@@ -2135,12 +2116,6 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
wind->server_decoration = NULL;
}
// Be sure to detach after this is done, otherwise ShowWindow crashes!
if (wind->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) {
wl_surface_attach(wind->surface, NULL, 0, 0);
wl_surface_commit(wind->surface);
}
// Clean up the export handle.
if (wind->exported) {
zxdg_exported_v2_destroy(wind->exported);
@@ -2158,26 +2133,31 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_unref(wind->shell_surface.libdecor.frame);
wind->shell_surface.libdecor.frame = NULL;
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
}
} else
#endif
{
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) {
Wayland_ReleasePopup(_this, window);
} else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel);
wind->shell_surface.xdg.toplevel.xdg_toplevel = NULL;
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
}
if (wind->shell_surface.xdg.surface) {
xdg_surface_destroy(wind->shell_surface.xdg.surface);
wind->shell_surface.xdg.surface = NULL;
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
Wayland_ReleasePopup(_this, window);
} else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel);
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL);
}
if (wind->shell_surface.xdg.surface) {
xdg_surface_destroy(wind->shell_surface.xdg.surface);
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, NULL);
}
}
// Attach a null buffer to unmap the surface.
wl_surface_attach(wind->surface, NULL, 0, 0);
wl_surface_commit(wind->surface);
SDL_zero(wind->shell_surface);
wind->show_hide_sync_required = true;
struct wl_callback *cb = wl_display_sync(_this->internal->display);
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
@@ -2991,6 +2971,27 @@ bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window)
return true;
}
bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable)
{
if (window->flags & SDL_WINDOW_POPUP_MENU) {
if (!(window->flags & SDL_WINDOW_HIDDEN)) {
if (!focusable && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
Wayland_SetKeyboardFocus(new_focus, set_focus);
} else if (focusable) {
if (SDL_ShouldFocusPopup(window)) {
Wayland_SetKeyboardFocus(window, true);
}
}
}
return true;
}
return SDL_SetError("wayland: focus can only be toggled on popup menu windows");
}
void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
{
SDL_WindowData *wind = window->internal;
+1 -4
View File
@@ -48,7 +48,6 @@ struct SDL_WindowData
struct
{
struct libdecor_frame *frame;
bool initial_configure_seen;
} libdecor;
#endif
struct
@@ -66,7 +65,6 @@ struct SDL_WindowData
struct xdg_positioner *xdg_positioner;
} popup;
};
bool initial_configure_seen;
} xdg;
} shell_surface;
enum
@@ -125,8 +123,6 @@ struct SDL_WindowData
SDL_DisplayData **outputs;
int num_outputs;
SDL_Window *keyboard_focus;
char *app_id;
double scale_factor;
@@ -237,6 +233,7 @@ extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern bool Wayland_SuspendScreenSaver(SDL_VideoDevice *_this);
extern bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
extern bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
extern float Wayland_GetWindowContentScale(SDL_VideoDevice *_this, SDL_Window *window);
extern void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
+5 -1
View File
@@ -385,7 +385,7 @@ static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus, DWORD pos)
}
}
SDL_SetKeyboardFocus(data->keyboard_focus ? data->keyboard_focus : window);
SDL_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window);
// In relative mode we are guaranteed to have mouse focus if we have keyboard focus
if (!SDL_GetMouse()->relative_mode) {
@@ -732,6 +732,10 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
float fAmount = (float)amount / WHEEL_DELTA;
SDL_SendMouseWheel(WIN_GetEventTimestamp(), window, mouseID, fAmount, 0.0f, SDL_MOUSEWHEEL_NORMAL);
}
/* Invalidate the mouse button flags. If we don't do this then disabling raw input
will cause held down mouse buttons to persist when released. */
windowdata->mouse_button_flags = (WPARAM)-1;
}
}
+6
View File
@@ -277,6 +277,9 @@ static void GAMEINPUT_InitialMouseReading(WIN_GameInputData *data, SDL_Window *w
bool down = ((state.buttons & mask) != 0);
SDL_SendMouseButton(timestamp, window, mouseID, GAMEINPUT_button_map[i], down);
}
// Invalidate mouse button flags
window->internal->mouse_button_flags = (WPARAM)-1;
}
}
@@ -307,6 +310,9 @@ static void GAMEINPUT_HandleMouseDelta(WIN_GameInputData *data, SDL_Window *wind
SDL_SendMouseButton(timestamp, window, mouseID, GAMEINPUT_button_map[i], down);
}
}
// Invalidate mouse button flags
window->internal->mouse_button_flags = (WPARAM)-1;
}
if (delta.wheelX || delta.wheelY) {
float fAmountX = (float)delta.wheelX / WHEEL_DELTA;
+2
View File
@@ -112,7 +112,9 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param)
}
devices[0].dwFlags |= RIDEV_REMOVE;
devices[0].hwndTarget = NULL;
devices[1].dwFlags |= RIDEV_REMOVE;
devices[1].hwndTarget = NULL;
RegisterRawInputDevices(devices, count, sizeof(devices[0]));
DestroyWindow(window);
+71 -132
View File
@@ -33,6 +33,7 @@
#include "../SDL_sysvideo.h"
#include "SDL_windowsvideo.h"
#include "SDL_windowskeyboard.h"
#include "SDL_windowswindow.h"
// Dropfile support
@@ -91,12 +92,6 @@ typedef void (NTAPI *RtlGetVersion_t)(NT_OSVERSIONINFOW *);
// #define HIGHDPI_DEBUG
// Fake window to help with DirectInput events.
HWND SDL_HelperWindow = NULL;
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
static const TCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
static ATOM SDL_HelperWindowClass = 0;
/* For borderless Windows, still want the following flag:
- WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc.
Additionally, non-fullscreen windows can add:
@@ -638,7 +633,7 @@ static void CleanupWindowData(SDL_VideoDevice *_this, SDL_Window *window)
static void WIN_ConstrainPopup(SDL_Window *window, bool output_to_pending)
{
// Clamp popup windows to the output borders
// Possibly clamp popup windows to the output borders
if (SDL_WINDOW_IS_POPUP(window)) {
SDL_Window *w;
SDL_DisplayID displayID;
@@ -649,28 +644,30 @@ static void WIN_ConstrainPopup(SDL_Window *window, bool output_to_pending)
const int height = window->last_size_pending ? window->pending.h : window->floating.h;
int offset_x = 0, offset_y = 0;
// Calculate the total offset from the parents
for (w = window->parent; SDL_WINDOW_IS_POPUP(w); w = w->parent) {
if (window->constrain_popup) {
// Calculate the total offset from the parents
for (w = window->parent; SDL_WINDOW_IS_POPUP(w); w = w->parent) {
offset_x += w->x;
offset_y += w->y;
}
offset_x += w->x;
offset_y += w->y;
}
abs_x += offset_x;
abs_y += offset_y;
offset_x += w->x;
offset_y += w->y;
abs_x += offset_x;
abs_y += offset_y;
// Constrain the popup window to the display of the toplevel parent
displayID = SDL_GetDisplayForWindow(w);
SDL_GetDisplayBounds(displayID, &rect);
if (abs_x + width > rect.x + rect.w) {
abs_x -= (abs_x + width) - (rect.x + rect.w);
// Constrain the popup window to the display of the toplevel parent
displayID = SDL_GetDisplayForWindow(w);
SDL_GetDisplayBounds(displayID, &rect);
if (abs_x + width > rect.x + rect.w) {
abs_x -= (abs_x + width) - (rect.x + rect.w);
}
if (abs_y + height > rect.y + rect.h) {
abs_y -= (abs_y + height) - (rect.y + rect.h);
}
abs_x = SDL_max(abs_x, rect.x);
abs_y = SDL_max(abs_y, rect.y);
}
if (abs_y + height > rect.y + rect.h) {
abs_y -= (abs_y + height) - (rect.y + rect.h);
}
abs_x = SDL_max(abs_x, rect.x);
abs_y = SDL_max(abs_y, rect.y);
if (output_to_pending) {
window->pending.x = abs_x - offset_x;
@@ -695,7 +692,7 @@ static void WIN_SetKeyboardFocus(SDL_Window *window, bool set_active_focus)
toplevel = toplevel->parent;
}
toplevel->internal->keyboard_focus = window;
toplevel->keyboard_focus = window;
if (set_active_focus && !window->is_hiding && !window->is_destroying) {
SDL_SetKeyboardFocus(window);
@@ -750,6 +747,9 @@ bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
return false;
}
// Ensure that the IME isn't active on the new window until explicitly requested.
WIN_StopTextInput(_this, window);
// Inform Windows of the frame change so we can respond to WM_NCCALCSIZE
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
@@ -1068,8 +1068,8 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
data->showing_window = false;
if (window->flags & SDL_WINDOW_POPUP_MENU && bActivate) {
WIN_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE) && bActivate) {
WIN_SetKeyboardFocus(window, true);
}
if (window->flags & SDL_WINDOW_MODAL) {
WIN_SetWindowModal(_this, window, true);
@@ -1086,21 +1086,10 @@ void WIN_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
ShowWindow(hwnd, SW_HIDE);
// Transfer keyboard focus back to the parent
if (window->flags & SDL_WINDOW_POPUP_MENU) {
SDL_Window *new_focus = window->parent;
bool set_focus = window == SDL_GetKeyboardFocus();
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed.
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
new_focus = new_focus->parent;
// If some window in the chain currently had keyboard focus, set it to the new lowest-level window.
if (!set_focus) {
set_focus = new_focus == SDL_GetKeyboardFocus();
}
}
// Transfer keyboard focus back to the parent from a grabbing popup.
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
WIN_SetKeyboardFocus(new_focus, set_focus);
}
}
@@ -1138,7 +1127,7 @@ void WIN_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
if (bActivate) {
SetForegroundWindow(hwnd);
if (window->flags & SDL_WINDOW_POPUP_MENU) {
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
WIN_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
}
} else {
@@ -1515,72 +1504,6 @@ void WIN_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
CleanupWindowData(_this, window);
}
/*
* Creates a HelperWindow used for DirectInput.
*/
bool SDL_HelperWindowCreate(void)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASS wce;
// Make sure window isn't created twice.
if (SDL_HelperWindow != NULL) {
return true;
}
// Create the class.
SDL_zero(wce);
wce.lpfnWndProc = DefWindowProc;
wce.lpszClassName = SDL_HelperWindowClassName;
wce.hInstance = hInstance;
// Register the class.
SDL_HelperWindowClass = RegisterClass(&wce);
if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
return WIN_SetError("Unable to create Helper Window Class");
}
// Create the window.
SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
SDL_HelperWindowName,
WS_OVERLAPPED, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, HWND_MESSAGE, NULL,
hInstance, NULL);
if (!SDL_HelperWindow) {
UnregisterClass(SDL_HelperWindowClassName, hInstance);
return WIN_SetError("Unable to create Helper Window");
}
return true;
}
/*
* Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
*/
void SDL_HelperWindowDestroy(void)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
// Destroy the window.
if (SDL_HelperWindow != NULL) {
if (DestroyWindow(SDL_HelperWindow) == 0) {
WIN_SetError("Unable to destroy Helper Window");
return;
}
SDL_HelperWindow = NULL;
}
// Unregister the class.
if (SDL_HelperWindowClass != 0) {
if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
WIN_SetError("Unable to destroy Helper Window Class");
return;
}
SDL_HelperWindowClass = 0;
}
}
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
void WIN_OnWindowEnter(SDL_VideoDevice *_this, SDL_Window *window)
{
@@ -2254,24 +2177,40 @@ void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
bool WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable)
{
SDL_WindowData *data = window->internal;
HWND hwnd = data->hwnd;
const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
if (!SDL_WINDOW_IS_POPUP(window)) {
SDL_WindowData *data = window->internal;
HWND hwnd = data->hwnd;
const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
SDL_assert(style != 0);
SDL_assert(style != 0);
if (focusable) {
if (style & WS_EX_NOACTIVATE) {
if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_NOACTIVATE) == 0) {
return WIN_SetError("SetWindowLong()");
if (focusable) {
if (style & WS_EX_NOACTIVATE) {
if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_NOACTIVATE) == 0) {
return WIN_SetError("SetWindowLong()");
}
}
} else {
if (!(style & WS_EX_NOACTIVATE)) {
if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE) == 0) {
return WIN_SetError("SetWindowLong()");
}
}
}
} else {
if (!(style & WS_EX_NOACTIVATE)) {
if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE) == 0) {
return WIN_SetError("SetWindowLong()");
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
if (!(window->flags & SDL_WINDOW_HIDDEN)) {
if (!focusable && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
WIN_SetKeyboardFocus(new_focus, set_focus);
} else if (focusable) {
if (SDL_ShouldFocusPopup(window)) {
WIN_SetKeyboardFocus(window, true);
}
}
}
return true;
}
return true;
@@ -2281,38 +2220,38 @@ bool WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool foc
void WIN_UpdateDarkModeForHWND(HWND hwnd)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
SDL_SharedObject *ntdll = SDL_LoadObject("ntdll.dll");
HMODULE ntdll = LoadLibrary(TEXT("ntdll.dll"));
if (!ntdll) {
return;
}
// There is no function to get Windows build number, so let's get it here via RtlGetVersion
RtlGetVersion_t RtlGetVersionFunc = (RtlGetVersion_t)SDL_LoadFunction(ntdll, "RtlGetVersion");
RtlGetVersion_t RtlGetVersionFunc = (RtlGetVersion_t)GetProcAddress(ntdll, "RtlGetVersion");
NT_OSVERSIONINFOW os_info;
os_info.dwOSVersionInfoSize = sizeof(NT_OSVERSIONINFOW);
os_info.dwBuildNumber = 0;
if (RtlGetVersionFunc) {
RtlGetVersionFunc(&os_info);
}
SDL_UnloadObject(ntdll);
FreeLibrary(ntdll);
os_info.dwBuildNumber &= ~0xF0000000;
if (os_info.dwBuildNumber < 17763) {
// Too old to support dark mode
return;
}
SDL_SharedObject *uxtheme = SDL_LoadObject("uxtheme.dll");
HMODULE uxtheme = LoadLibrary(TEXT("uxtheme.dll"));
if (!uxtheme) {
return;
}
RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyStateFunc = (RefreshImmersiveColorPolicyState_t)SDL_LoadFunction(uxtheme, MAKEINTRESOURCEA(104));
ShouldAppsUseDarkMode_t ShouldAppsUseDarkModeFunc = (ShouldAppsUseDarkMode_t)SDL_LoadFunction(uxtheme, MAKEINTRESOURCEA(132));
AllowDarkModeForWindow_t AllowDarkModeForWindowFunc = (AllowDarkModeForWindow_t)SDL_LoadFunction(uxtheme, MAKEINTRESOURCEA(133));
RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyStateFunc = (RefreshImmersiveColorPolicyState_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(104));
ShouldAppsUseDarkMode_t ShouldAppsUseDarkModeFunc = (ShouldAppsUseDarkMode_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(132));
AllowDarkModeForWindow_t AllowDarkModeForWindowFunc = (AllowDarkModeForWindow_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(133));
if (os_info.dwBuildNumber < 18362) {
AllowDarkModeForApp_t AllowDarkModeForAppFunc = (AllowDarkModeForApp_t)SDL_LoadFunction(uxtheme, MAKEINTRESOURCEA(135));
AllowDarkModeForApp_t AllowDarkModeForAppFunc = (AllowDarkModeForApp_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(135));
if (AllowDarkModeForAppFunc) {
AllowDarkModeForAppFunc(true);
}
} else {
SetPreferredAppMode_t SetPreferredAppModeFunc = (SetPreferredAppMode_t)SDL_LoadFunction(uxtheme, MAKEINTRESOURCEA(135));
SetPreferredAppMode_t SetPreferredAppModeFunc = (SetPreferredAppMode_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(135));
if (SetPreferredAppModeFunc) {
SetPreferredAppModeFunc(UXTHEME_APPMODE_ALLOW_DARK);
}
@@ -2330,7 +2269,7 @@ void WIN_UpdateDarkModeForHWND(HWND hwnd)
} else {
value = (SDL_GetSystemTheme() == SDL_SYSTEM_THEME_DARK) ? TRUE : FALSE;
}
SDL_UnloadObject(uxtheme);
FreeLibrary(uxtheme);
if (os_info.dwBuildNumber < 18362) {
SetProp(hwnd, TEXT("UseImmersiveDarkModeColors"), SDL_reinterpret_cast(HANDLE, SDL_static_cast(INT_PTR, value)));
} else {
-1
View File
@@ -93,7 +93,6 @@ struct SDL_WindowData
bool destroy_parent_with_window;
SDL_DisplayID last_displayID;
WCHAR *ICMFileName;
SDL_Window *keyboard_focus;
SDL_WindowEraseBackgroundMode hint_erase_background_mode;
struct SDL_VideoData *videodata;
#ifdef SDL_VIDEO_OPENGL_EGL
+11 -15
View File
@@ -194,7 +194,7 @@ static bool X11_KeyRepeat(Display *display, XEvent *event)
return d.found;
}
static bool X11_IsWheelEvent(Display *display, int button, int *xticks, int *yticks)
bool X11_IsWheelEvent(int button, int *xticks, int *yticks)
{
/* according to the xlib docs, no specific mouse wheel events exist.
However, the defacto standard is that the vertical wheel is X buttons
@@ -1016,8 +1016,6 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, float x, float y, unsigned long time)
{
SDL_Window *window = windowdata->window;
const SDL_VideoData *videodata = _this->internal;
Display *display = videodata->display;
int xticks = 0, yticks = 0;
Uint64 timestamp = X11_GetEventTimestamp(time);
@@ -1031,7 +1029,7 @@ void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, S
SDL_SendMouseMotion(timestamp, window, mouseID, false, x, y);
}
if (X11_IsWheelEvent(display, button, &xticks, &yticks)) {
if (X11_IsWheelEvent(button, &xticks, &yticks)) {
SDL_SendMouseWheel(timestamp, window, mouseID, (float)-xticks, (float)yticks, SDL_MOUSEWHEEL_NORMAL);
} else {
bool ignore_click = false;
@@ -1063,8 +1061,6 @@ void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, S
void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, unsigned long time)
{
SDL_Window *window = windowdata->window;
const SDL_VideoData *videodata = _this->internal;
Display *display = videodata->display;
// The X server sends a Release event for each Press for wheels. Ignore them.
int xticks = 0, yticks = 0;
Uint64 timestamp = X11_GetEventTimestamp(time);
@@ -1072,7 +1068,7 @@ void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata,
#ifdef DEBUG_XEVENTS
SDL_Log("window 0x%lx: ButtonRelease (X11 button = %d)", windowdata->xwindow, button);
#endif
if (!X11_IsWheelEvent(display, button, &xticks, &yticks)) {
if (!X11_IsWheelEvent(button, &xticks, &yticks)) {
if (button > 7) {
// see explanation at case ButtonPress
button -= (8 - SDL_BUTTON_X1);
@@ -1513,9 +1509,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
&ChildReturn);
}
/* Xfce sends ConfigureNotify before PropertyNotify when toggling fullscreen and maximized, which
* is backwards from every other window manager, as well as what is expected by SDL and its clients.
* Defer emitting the size/move events until the corresponding PropertyNotify arrives.
/* Some window managers send ConfigureNotify before PropertyNotify when changing state (Xfce and
* fvwm are known to do this), which is backwards from other window managers, as well as what is
* expected by SDL and its clients. Defer emitting the size/move events until the corresponding
* PropertyNotify arrives for consistency.
*/
const Uint32 changed = X11_GetNetWMState(_this, data->window, xevent->xproperty.window) ^ data->window->flags;
if (changed & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) {
@@ -1950,13 +1947,12 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
right approach, but it seems to work. */
X11_UpdateKeymap(_this, true);
} else if (xevent->xproperty.atom == videodata->atoms._NET_FRAME_EXTENTS) {
/* Events are disabled when leaving fullscreen until the borders appear to avoid
* incorrect size/position events.
*/
X11_GetBorderValues(data);
if (data->size_move_event_flags) {
/* Events are disabled when leaving fullscreen until the borders appear to avoid
* incorrect size/position events on compositing window managers.
*/
data->size_move_event_flags &= ~X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS;
X11_GetBorderValues(data);
}
if (!(data->window->flags & SDL_WINDOW_FULLSCREEN) && data->toggle_borders) {
data->toggle_borders = false;
+1
View File
@@ -36,5 +36,6 @@ extern void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *wind
extern SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window);
extern bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y, bool force_new_result);
extern bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y);
extern bool X11_IsWheelEvent(int button, int *xticks, int *yticks);
#endif // SDL_x11events_h_
+3
View File
@@ -30,7 +30,10 @@
#include <X11/keysym.h>
#include <locale.h>
#ifndef SDL_FORK_MESSAGEBOX
#define SDL_FORK_MESSAGEBOX 1
#endif
#define SDL_SET_LOCALE 1
#if SDL_FORK_MESSAGEBOX
+80 -47
View File
@@ -86,6 +86,23 @@ static Bool X11_XIfEventTimeout(Display *display, XEvent *event_return, Bool (*p
}
*/
static bool X11_CheckCurrentDesktop(const char *name)
{
SDL_Environment *env = SDL_GetEnvironment();
const char *desktopVar = SDL_GetEnvironmentVariable(env, "DESKTOP_SESSION");
if (desktopVar && SDL_strcasecmp(desktopVar, name) == 0) {
return true;
}
desktopVar = SDL_GetEnvironmentVariable(env, "XDG_CURRENT_DESKTOP");
if (desktopVar && SDL_strcasestr(desktopVar, name)) {
return true;
}
return false;
}
static bool X11_IsWindowMapped(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->internal;
@@ -215,28 +232,30 @@ static void X11_ConstrainPopup(SDL_Window *window, bool output_to_pending)
int abs_y = window->last_position_pending ? window->pending.y : window->floating.y;
int offset_x = 0, offset_y = 0;
// Calculate the total offset from the parents
for (w = window->parent; SDL_WINDOW_IS_POPUP(w); w = w->parent) {
if (window->constrain_popup) {
// Calculate the total offset from the parents
for (w = window->parent; SDL_WINDOW_IS_POPUP(w); w = w->parent) {
offset_x += w->x;
offset_y += w->y;
}
offset_x += w->x;
offset_y += w->y;
}
abs_x += offset_x;
abs_y += offset_y;
offset_x += w->x;
offset_y += w->y;
abs_x += offset_x;
abs_y += offset_y;
displayID = SDL_GetDisplayForWindow(w);
displayID = SDL_GetDisplayForWindow(w);
SDL_GetDisplayBounds(displayID, &rect);
if (abs_x + window->w > rect.x + rect.w) {
abs_x -= (abs_x + window->w) - (rect.x + rect.w);
SDL_GetDisplayBounds(displayID, &rect);
if (abs_x + window->w > rect.x + rect.w) {
abs_x -= (abs_x + window->w) - (rect.x + rect.w);
}
if (abs_y + window->h > rect.y + rect.h) {
abs_y -= (abs_y + window->h) - (rect.y + rect.h);
}
abs_x = SDL_max(abs_x, rect.x);
abs_y = SDL_max(abs_y, rect.y);
}
if (abs_y + window->h > rect.y + rect.h) {
abs_y -= (abs_y + window->h) - (rect.y + rect.h);
}
abs_x = SDL_max(abs_x, rect.x);
abs_y = SDL_max(abs_y, rect.y);
if (output_to_pending) {
window->pending.x = abs_x - offset_x;
@@ -257,7 +276,7 @@ static void X11_SetKeyboardFocus(SDL_Window *window, bool set_active_focus)
toplevel = toplevel->parent;
}
toplevel->internal->keyboard_focus = window;
toplevel->keyboard_focus = window;
if (set_active_focus && !window->is_hiding && !window->is_destroying) {
SDL_SetKeyboardFocus(window);
@@ -1542,9 +1561,9 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
X11_XFlush(display);
}
// Popup menus grab the keyboard
if (window->flags & SDL_WINDOW_POPUP_MENU) {
X11_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
// Grabbing popup menus get keyboard focus.
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
X11_SetKeyboardFocus(window, true);
}
// Get some valid border values, if we haven't received them yet
@@ -1566,6 +1585,15 @@ void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
X11_XMoveWindow(display, data->xwindow, x, y);
}
/* XMonad ignores size hints and shrinks the client area to overlay borders on fixed-size windows,
* even if no borders were requested, resulting in the window client area being smaller than
* requested. Calling XResizeWindow after mapping seems to fix it, even though resizing fixed-size
* windows in this manner doesn't work on any other window manager.
*/
if (!(window->flags & SDL_WINDOW_RESIZABLE) && X11_CheckCurrentDesktop("xmonad")) {
X11_XResizeWindow(display, data->xwindow, window->w, window->h);
}
/* Some window managers can send garbage coordinates while mapping the window, so don't emit size and position
* events during the initial configure events.
*/
@@ -1607,20 +1635,9 @@ void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
// Transfer keyboard focus back to the parent
if (window->flags & SDL_WINDOW_POPUP_MENU) {
SDL_Window *new_focus = window->parent;
bool set_focus = window == SDL_GetKeyboardFocus();
// Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed.
while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) {
new_focus = new_focus->parent;
// If some window in the chain currently had focus, set it to the new lowest-level window.
if (!set_focus) {
set_focus = new_focus == SDL_GetKeyboardFocus();
}
}
if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
X11_SetKeyboardFocus(new_focus, set_focus);
}
@@ -2338,21 +2355,37 @@ bool X11_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window)
bool X11_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable)
{
SDL_WindowData *data = window->internal;
Display *display = data->videodata->display;
XWMHints *wmhints;
if (!SDL_WINDOW_IS_POPUP(window)) {
SDL_WindowData *data = window->internal;
Display *display = data->videodata->display;
XWMHints *wmhints;
wmhints = X11_XGetWMHints(display, data->xwindow);
if (!wmhints) {
return SDL_SetError("Couldn't get WM hints");
wmhints = X11_XGetWMHints(display, data->xwindow);
if (!wmhints) {
return SDL_SetError("Couldn't get WM hints");
}
wmhints->input = focusable ? True : False;
wmhints->flags |= InputHint;
X11_XSetWMHints(display, data->xwindow, wmhints);
X11_XFree(wmhints);
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
if (!(window->flags & SDL_WINDOW_HIDDEN)) {
if (!focusable && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
SDL_Window *new_focus;
const bool set_focus = SDL_ShouldRelinquishPopupFocus(window, &new_focus);
X11_SetKeyboardFocus(new_focus, set_focus);
} else if (focusable) {
if (SDL_ShouldFocusPopup(window)) {
X11_SetKeyboardFocus(window, true);
}
}
}
return true;
}
wmhints->input = focusable ? True : False;
wmhints->flags |= InputHint;
X11_XSetWMHints(display, data->xwindow, wmhints);
X11_XFree(wmhints);
return true;
}
-1
View File
@@ -75,7 +75,6 @@ struct SDL_WindowData
Window xdnd_source;
bool flashing_window;
Uint64 flash_cancel_time;
SDL_Window *keyboard_focus;
#ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
+12 -4
View File
@@ -406,11 +406,15 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
case XI_ButtonRelease:
{
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->deviceid);
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->sourceid);
const int button = xev->detail;
const bool down = (cookie->evtype == XI_ButtonPress);
if (pen) {
if (xev->deviceid != xev->sourceid) {
// Discard events from "Master" devices to avoid duplicates.
break;
}
// Only report button event; if there was also pen movement / pressure changes, we expect an XI_Motion event first anyway.
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
if (button == 1) { // button 1 is the pen tip
@@ -421,9 +425,12 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
} else {
// Otherwise assume a regular mouse
SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, xev->event);
int x_ticks = 0, y_ticks = 0;
if (xev->deviceid != xev->sourceid) {
// Discard events from "Master" devices to avoid duplicates.
/* Discard wheel events from "Master" devices to avoid duplicates,
* as coarse wheel events are stateless and can't be deduplicated.
*/
if (xev->deviceid != xev->sourceid && X11_IsWheelEvent(button, &x_ticks, &y_ticks)) {
break;
}
@@ -449,7 +456,8 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
videodata->global_mouse_changed = true;
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->deviceid);
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->sourceid);
if (pen) {
if (xev->deviceid != xev->sourceid) {
// Discard events from "Master" devices to avoid duplicates.
+1 -1
View File
@@ -411,7 +411,7 @@ add_sdl_test_executable(testdialog SOURCES testdialog.c)
add_sdl_test_executable(testtime SOURCES testtime.c)
add_sdl_test_executable(testmanymouse SOURCES testmanymouse.c)
add_sdl_test_executable(testmodal SOURCES testmodal.c)
add_sdl_test_executable(testtray SOURCES testtray.c)
add_sdl_test_executable(testtray NEEDS_RESOURCES TESTUTILS SOURCES testtray.c)
add_sdl_test_executable(testprocess
+44
View File
@@ -989,6 +989,45 @@ static int SDLCALL surface_testBlitInvalid(void *arg)
return TEST_COMPLETED;
}
static int SDLCALL surface_testBlitsWithBadCoordinates(void *arg)
{
const SDL_Rect rect[8] = {
{ SDL_MAX_SINT32, 0, 2, 2 },
{ 0, SDL_MAX_SINT32, 2, 2 },
{ 0, 0, SDL_MAX_SINT32, 2 },
{ 0, 0, 2, SDL_MAX_SINT32 },
{ SDL_MIN_SINT32, 0, 2, 2 },
{ 0, SDL_MIN_SINT32, 2, 2 },
{ 0, 0, SDL_MIN_SINT32, 2 },
{ 0, 0, 2, SDL_MIN_SINT32 }
};
SDL_Surface *s;
bool result;
int i;
s = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_RGBA8888);
SDLTest_AssertCheck(s != NULL, "Check surface creation");
for (i = 0; i < 8; i++) {
result = SDL_BlitSurface(s, NULL, s, &rect[i]);
SDLTest_AssertCheck(result == true, "SDL_BlitSurface(valid, NULL, valid, &rect), result = %s", result ? "true" : "false");
result = SDL_BlitSurface(s, &rect[i], s, NULL);
SDLTest_AssertCheck(result == true, "SDL_BlitSurface(valid, &rect, valid, NULL), result = %s", result ? "true" : "false");
result = SDL_BlitSurfaceScaled(s, NULL, s, &rect[i], SDL_SCALEMODE_NEAREST);
SDLTest_AssertCheck(result == true, "SDL_BlitSurfaceScaled(valid, NULL, valid, &rect, SDL_SCALEMODE_NEAREST), result = %s", result ? "true" : "false");
result = SDL_BlitSurfaceScaled(s, &rect[i], s, NULL, SDL_SCALEMODE_NEAREST);
SDLTest_AssertCheck(result == true, "SDL_BlitSurfaceScaled(valid, &rect, valid, NULL, SDL_SCALEMODE_NEAREST), result = %s", result ? "true" : "false");
}
SDL_DestroySurface(s);
return TEST_COMPLETED;
}
static int SDLCALL surface_testOverflow(void *arg)
{
char buf[1024];
@@ -1664,6 +1703,10 @@ static const SDLTest_TestCaseReference surfaceTestBlitInvalid = {
surface_testBlitInvalid, "surface_testBlitInvalid", "Tests blitting routines with invalid surfaces.", TEST_ENABLED
};
static const SDLTest_TestCaseReference surfaceTestBlitsWithBadCoordinates = {
surface_testBlitsWithBadCoordinates, "surface_testBlitsWithBadCoordinates", "Test blitting routines with bad coordinates.", TEST_ENABLED
};
static const SDLTest_TestCaseReference surfaceTestOverflow = {
surface_testOverflow, "surface_testOverflow", "Test overflow detection.", TEST_ENABLED
};
@@ -1713,6 +1756,7 @@ static const SDLTest_TestCaseReference *surfaceTests[] = {
&surfaceTestBlitBlendMod,
&surfaceTestBlitBlendMul,
&surfaceTestBlitInvalid,
&surfaceTestBlitsWithBadCoordinates,
&surfaceTestOverflow,
&surfaceTestFlip,
&surfaceTestPalette,
+17
View File
@@ -679,6 +679,16 @@ void SetupVulkanRenderProperties(VulkanVideoContext *context, SDL_PropertiesID p
SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER, context->graphicsQueueFamilyIndex);
}
#if LIBAVUTIL_VERSION_MAJOR >= 59
static void AddQueueFamily(AVVulkanDeviceContext *ctx, int idx, int num, VkQueueFlagBits flags)
{
AVVulkanDeviceQueueFamily *entry = &ctx->qf[ctx->nb_qf++];
entry->idx = idx;
entry->num = num;
entry->flags = flags;
}
#endif /* LIBAVUTIL_VERSION_MAJOR */
void SetupVulkanDeviceContextData(VulkanVideoContext *context, AVVulkanDeviceContext *ctx)
{
ctx->get_proc_addr = context->vkGetInstanceProcAddr;
@@ -690,6 +700,12 @@ void SetupVulkanDeviceContextData(VulkanVideoContext *context, AVVulkanDeviceCon
ctx->nb_enabled_inst_extensions = context->instanceExtensionsCount;
ctx->enabled_dev_extensions = context->deviceExtensions;
ctx->nb_enabled_dev_extensions = context->deviceExtensionsCount;
#if LIBAVUTIL_VERSION_MAJOR >= 59
AddQueueFamily(ctx, context->graphicsQueueFamilyIndex, context->graphicsQueueCount, VK_QUEUE_GRAPHICS_BIT);
AddQueueFamily(ctx, context->transferQueueFamilyIndex, context->transferQueueCount, VK_QUEUE_TRANSFER_BIT);
AddQueueFamily(ctx, context->computeQueueFamilyIndex, context->computeQueueCount, VK_QUEUE_COMPUTE_BIT);
AddQueueFamily(ctx, context->decodeQueueFamilyIndex, context->decodeQueueCount, VK_QUEUE_VIDEO_DECODE_BIT_KHR);
#else
ctx->queue_family_index = context->graphicsQueueFamilyIndex;
ctx->nb_graphics_queues = context->graphicsQueueCount;
ctx->queue_family_tx_index = context->transferQueueFamilyIndex;
@@ -700,6 +716,7 @@ void SetupVulkanDeviceContextData(VulkanVideoContext *context, AVVulkanDeviceCon
ctx->nb_encode_queues = 0;
ctx->queue_family_decode_index = context->decodeQueueFamilyIndex;
ctx->nb_decode_queues = context->decodeQueueCount;
#endif /* LIBAVUTIL_VERSION_MAJOR */
}
static int CreateCommandBuffers(VulkanVideoContext *context, SDL_Renderer *renderer)
+1 -1
View File
@@ -97,7 +97,7 @@ int main(int argc, char *argv[])
}
if (e.key.key == SDLK_M) {
if (SDL_SetWindowParent(w2, w2)) {
if (SDL_SetWindowParent(w2, w1)) {
if (SDL_SetWindowModal(w2, true)) {
SDL_SetWindowTitle(w2, "Modal Window");
}
+43 -5
View File
@@ -49,6 +49,9 @@ struct PopupWindow
static struct PopupWindow *menus;
static struct PopupWindow tooltip;
static bool no_constraints;
static bool no_grab;
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void quit(int rc)
{
@@ -95,14 +98,27 @@ static bool create_popup(struct PopupWindow *new_popup, bool is_menu)
const int w = is_menu ? MENU_WIDTH : TOOLTIP_WIDTH;
const int h = is_menu ? MENU_HEIGHT : TOOLTIP_HEIGHT;
const int v_off = is_menu ? 0 : 32;
const SDL_WindowFlags flags = is_menu ? SDL_WINDOW_POPUP_MENU : SDL_WINDOW_TOOLTIP;
float x, y;
focus = SDL_GetMouseFocus();
SDL_GetMouseState(&x, &y);
new_win = SDL_CreatePopupWindow(focus,
(int)x, (int)y + v_off, w, h, flags);
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, focus);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN, !no_constraints);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, !no_grab);
if (is_menu) {
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, true);
} else {
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN, true);
}
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, (int)x);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, (int)y + v_off);
new_win = SDL_CreateWindowWithProperties(props);
SDL_DestroyProperties(props);
if (new_win) {
new_renderer = SDL_CreateRenderer(new_win, state->renderdriver);
@@ -249,8 +265,30 @@ int main(int argc, char *argv[])
}
/* Parse commandline */
if (!SDLTest_CommonDefaultArgs(state, argc, argv)) {
return 1;
for (i = 1; i < argc;) {
int consumed;
consumed = SDLTest_CommonArg(state, i);
if (consumed == 0) {
consumed = -1;
if (SDL_strcasecmp(argv[i], "--no-constraints") == 0) {
no_constraints = true;
consumed = 1;
} else if (SDL_strcasecmp(argv[i], "--no-grab") == 0) {
no_grab = true;
consumed = 1;
}
}
if (consumed < 0) {
static const char *options[] = {
"[--no-constraints]",
"[--no-grab]",
NULL
};
SDLTest_CommonLogUsage(state, argv[0], options);
return 1;
}
i += consumed;
}
if (!SDLTest_CommonInit(state)) {
+7 -3
View File
@@ -1,3 +1,4 @@
#include "testutils.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_test.h>
@@ -520,14 +521,17 @@ int main(int argc, char **argv)
goto quit;
}
/* TODO: Resource paths? */
SDL_Surface *icon = SDL_LoadBMP("../test/sdl-test_round.bmp");
char *icon1filename = GetResourceFilename(NULL, "sdl-test_round.bmp");
SDL_Surface *icon = SDL_LoadBMP(icon1filename);
SDL_free(icon1filename);
if (!icon) {
SDL_Log("Couldn't load icon 1, proceeding without: %s", SDL_GetError());
}
SDL_Surface *icon2 = SDL_LoadBMP("../test/speaker.bmp");
char *icon2filename = GetResourceFilename(NULL, "speaker.bmp");
SDL_Surface *icon2 = SDL_LoadBMP(icon2filename);
SDL_free(icon2filename);
if (!icon2) {
SDL_Log("Couldn't load icon 2, proceeding without: %s", SDL_GetError());
+1 -1
View File
@@ -28,7 +28,7 @@ third-party/sqlite3:
third-party/fmt:
git: https://github.com/fmtlib/fmt/tree/11.1.4
third-party/SDL:
git: https://github.com/libsdl-org/SDL/tree/release-3.2.16
git: https://github.com/libsdl-org/SDL/tree/release-3.2.20
third-party/imgui:
git: https://github.com/ocornut/imgui/releases/tag/v1.91.8
third-party/tree-sitter: