diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6493b72b2a..13c50ec7ab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -536,7 +536,7 @@ jobs: uses: nttld/setup-ndk@v1 with: local-cache: true - ndk-version: r21e + ndk-version: r28c - name: 'Setup Java JDK' uses: actions/setup-java@v4 with: diff --git a/Android.mk b/Android.mk index 0f3138e5f4..3ecc631d10 100644 --- a/Android.mk +++ b/Android.mk @@ -108,10 +108,6 @@ 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 156c18edf4..735ece5e4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,29 +184,6 @@ if(MSVC) set(SDL_RELOCATABLE_DEFAULT ON) endif() -if(MSVC) - if(NOT SDL_LIBC) - # 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_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) - # clang-cl treats /W4 as '-Wall -Wextra' -- we don't need -Wextra - foreach(flag_var - CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE - CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) - string(REGEX REPLACE "/W4" "/W3" ${flag_var} "${${flag_var}}") - endforeach(flag_var) - endif() -endif() - set(SDL_SHARED_DEFAULT ON) set(SDL_STATIC_DEFAULT ON) @@ -444,6 +421,29 @@ if(SDL_PRESEED) SDL_Preseed_CMakeCache() endif() +if(MSVC) + if(NOT SDL_LIBC) + # 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_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) + # clang-cl treats /W4 as '-Wall -Wextra' -- we don't need -Wextra + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) + string(REGEX REPLACE "/W4" "/W3" ${flag_var} "${${flag_var}}") + endforeach(flag_var) + endif() +endif() + if(SDL_SHARED) add_library(SDL3-shared SHARED) add_library(SDL3::SDL3-shared ALIAS SDL3-shared) @@ -1191,34 +1191,63 @@ endif() # General source files sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/*.c" + "${SDL3_SOURCE_DIR}/src/*.h" "${SDL3_SOURCE_DIR}/src/atomic/*.c" + "${SDL3_SOURCE_DIR}/src/atomic/*.h" "${SDL3_SOURCE_DIR}/src/audio/*.c" + "${SDL3_SOURCE_DIR}/src/audio/*.h" "${SDL3_SOURCE_DIR}/src/camera/*.c" + "${SDL3_SOURCE_DIR}/src/camera/*.h" "${SDL3_SOURCE_DIR}/src/core/*.c" + "${SDL3_SOURCE_DIR}/src/core/*.h" "${SDL3_SOURCE_DIR}/src/cpuinfo/*.c" + "${SDL3_SOURCE_DIR}/src/cpuinfo/*.h" "${SDL3_SOURCE_DIR}/src/dynapi/*.c" + "${SDL3_SOURCE_DIR}/src/dynapi/*.h" "${SDL3_SOURCE_DIR}/src/events/*.c" + "${SDL3_SOURCE_DIR}/src/events/*.h" "${SDL3_SOURCE_DIR}/src/io/*.c" + "${SDL3_SOURCE_DIR}/src/io/*.h" "${SDL3_SOURCE_DIR}/src/io/generic/*.c" + "${SDL3_SOURCE_DIR}/src/io/generic/*.h" "${SDL3_SOURCE_DIR}/src/filesystem/*.c" + "${SDL3_SOURCE_DIR}/src/filesystem/*.h" "${SDL3_SOURCE_DIR}/src/gpu/*.c" + "${SDL3_SOURCE_DIR}/src/gpu/*.h" "${SDL3_SOURCE_DIR}/src/joystick/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/*.h" "${SDL3_SOURCE_DIR}/src/haptic/*.c" + "${SDL3_SOURCE_DIR}/src/haptic/*.h" "${SDL3_SOURCE_DIR}/src/hidapi/*.c" + "${SDL3_SOURCE_DIR}/src/hidapi/*.h" "${SDL3_SOURCE_DIR}/src/locale/*.c" + "${SDL3_SOURCE_DIR}/src/locale/*.h" "${SDL3_SOURCE_DIR}/src/main/*.c" + "${SDL3_SOURCE_DIR}/src/main/*.h" "${SDL3_SOURCE_DIR}/src/misc/*.c" + "${SDL3_SOURCE_DIR}/src/misc/*.h" "${SDL3_SOURCE_DIR}/src/power/*.c" + "${SDL3_SOURCE_DIR}/src/power/*.h" "${SDL3_SOURCE_DIR}/src/render/*.c" + "${SDL3_SOURCE_DIR}/src/render/*.h" "${SDL3_SOURCE_DIR}/src/render/*/*.c" + "${SDL3_SOURCE_DIR}/src/render/*/*.h" "${SDL3_SOURCE_DIR}/src/sensor/*.c" + "${SDL3_SOURCE_DIR}/src/sensor/*.h" "${SDL3_SOURCE_DIR}/src/stdlib/*.c" + "${SDL3_SOURCE_DIR}/src/stdlib/*.h" "${SDL3_SOURCE_DIR}/src/storage/*.c" + "${SDL3_SOURCE_DIR}/src/storage/*.h" "${SDL3_SOURCE_DIR}/src/thread/*.c" + "${SDL3_SOURCE_DIR}/src/thread/*.h" "${SDL3_SOURCE_DIR}/src/time/*.c" + "${SDL3_SOURCE_DIR}/src/time/*.h" "${SDL3_SOURCE_DIR}/src/timer/*.c" + "${SDL3_SOURCE_DIR}/src/timer/*.h" "${SDL3_SOURCE_DIR}/src/video/*.c" + "${SDL3_SOURCE_DIR}/src/video/*.h" "${SDL3_SOURCE_DIR}/src/video/yuv2rgb/*.c" + "${SDL3_SOURCE_DIR}/src/video/yuv2rgb/*.h" ) # Build uclibc as a static library such that non-used symbols don't end up in the SDL3 shared library. @@ -1258,13 +1287,19 @@ if(SDL_AUDIO) # CheckDummyAudio/CheckDiskAudio - valid for all platforms if(SDL_DUMMYAUDIO) set(SDL_AUDIO_DRIVER_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/audio/dummy/*.h" + ) set(HAVE_DUMMYAUDIO TRUE) set(HAVE_SDL_AUDIO TRUE) endif() if(SDL_DISKAUDIO) set(SDL_AUDIO_DRIVER_DISK 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/disk/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/disk/*.c" + "${SDL3_SOURCE_DIR}/src/audio/disk/*.h" + ) set(HAVE_DISKAUDIO TRUE) set(HAVE_SDL_AUDIO TRUE) endif() @@ -1274,7 +1309,10 @@ if(SDL_CAMERA) # CheckDummyCamera/CheckDiskCamera - valid for all platforms if(SDL_DUMMYCAMERA) set(SDL_CAMERA_DRIVER_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/camera/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/camera/dummy/*.h" + ) set(HAVE_DUMMYCAMERA TRUE) set(HAVE_SDL_CAMERA TRUE) endif() @@ -1293,7 +1331,10 @@ if(UNIX OR APPLE) CheckDLOPEN() if(HAVE_DLOPEN) set(SDL_LOADSO_DLOPEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c" + "${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.h" + ) set(HAVE_SDL_LOADSO TRUE) endif() endif() @@ -1306,14 +1347,20 @@ if(SDL_JOYSTICK) if(SDL_VIRTUAL_JOYSTICK) set(HAVE_VIRTUAL_JOYSTICK TRUE) set(SDL_JOYSTICK_VIRTUAL 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/virtual/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/joystick/virtual/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/virtual/*.h" + ) endif() endif() if(SDL_VIDEO) if(SDL_DUMMYVIDEO) set(SDL_VIDEO_DRIVER_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/video/dummy/*.h" + ) set(HAVE_DUMMYVIDEO TRUE) set(HAVE_SDL_VIDEO TRUE) endif() @@ -1323,11 +1370,17 @@ endif() if(ANDROID) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/core/android/*.c" + "${SDL3_SOURCE_DIR}/src/core/android/*.h" + ) sdl_sources("${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") set_property(SOURCE "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/misc/android/*.c" + "${SDL3_SOURCE_DIR}/src/misc/android/*.h" + ) set(HAVE_SDL_MISC TRUE) # SDL_spinlock.c Needs to be compiled in ARM mode. @@ -1345,18 +1398,27 @@ if(ANDROID) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_OPENSLES 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/openslES/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/openslES/*.c" + "${SDL3_SOURCE_DIR}/src/audio/openslES/*.h" + ) sdl_link_dependency(opensles LIBS ${ANDROID_DL_LIBRARY} OpenSLES) set(SDL_AUDIO_DRIVER_AAUDIO 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/aaudio/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/aaudio/*.c" + "${SDL3_SOURCE_DIR}/src/audio/aaudio/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() set(SDL_FILESYSTEM_ANDROID 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/filesystem/android/*.c" + "${SDL3_SOURCE_DIR}/src/filesystem/android/*.h" + ) set(HAVE_SDL_FILESYSTEM TRUE) set(SDL_FSOPS_POSIX 1) # !!! FIXME: this might need something else for .apk data? @@ -1365,7 +1427,10 @@ if(ANDROID) if(SDL_HAPTIC) set(SDL_HAPTIC_ANDROID 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/haptic/android/*.c" + "${SDL3_SOURCE_DIR}/src/haptic/android/*.h" + ) set(HAVE_SDL_HAPTIC TRUE) endif() @@ -1375,46 +1440,71 @@ if(ANDROID) set(SDL_JOYSTICK_ANDROID 1) sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/joystick/android/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/android/*.h" ) set(HAVE_SDL_JOYSTICK TRUE) endif() set(SDL_LOADSO_DLOPEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c" + "${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.h" + ) set(HAVE_SDL_LOADSO TRUE) if(SDL_POWER) set(SDL_POWER_ANDROID 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/power/android/*.c" + "${SDL3_SOURCE_DIR}/src/power/android/*.h" + ) set(HAVE_SDL_POWER TRUE) endif() - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/locale/android/*.c" + "${SDL3_SOURCE_DIR}/src/locale/android/*.h" + ) set(HAVE_SDL_LOCALE TRUE) set(SDL_TIME_UNIX 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/time/unix/*.c" + "${SDL3_SOURCE_DIR}/src/time/unix/*.h" + ) set(HAVE_SDL_TIME TRUE) set(SDL_TIMER_UNIX 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/timer/unix/*.c" + "${SDL3_SOURCE_DIR}/src/timer/unix/*.h" + ) set(HAVE_SDL_TIMERS TRUE) if(SDL_SENSOR) set(SDL_SENSOR_ANDROID 1) set(HAVE_SDL_SENSORS TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/sensor/android/*.c" + "${SDL3_SOURCE_DIR}/src/sensor/android/*.h" + ) endif() if(SDL_CAMERA) set(SDL_CAMERA_DRIVER_ANDROID 1) set(HAVE_CAMERA TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/camera/android/*.c" + "${SDL3_SOURCE_DIR}/src/camera/android/*.h" + ) endif() if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_ANDROID 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/android/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/android/*.c" + "${SDL3_SOURCE_DIR}/src/video/android/*.h" + ) set(HAVE_SDL_VIDEO TRUE) # Core stuff @@ -1566,20 +1656,32 @@ elseif(EMSCRIPTEN) # project. Uncomment at will for verbose cross-compiling -I/../ path info. sdl_compile_options(PRIVATE "-Wno-warn-absolute-paths") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/main/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/main/emscripten/*.h" + ) set(HAVE_SDL_MAIN_CALLBACKS TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/misc/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/misc/emscripten/*.h" + ) set(HAVE_SDL_MISC TRUE) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_EMSCRIPTEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/audio/emscripten/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() set(SDL_FILESYSTEM_EMSCRIPTEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/filesystem/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/filesystem/emscripten/*.h" + ) set(HAVE_SDL_FILESYSTEM TRUE) set(SDL_FSOPS_POSIX 1) @@ -1589,30 +1691,48 @@ elseif(EMSCRIPTEN) if(SDL_CAMERA) set(SDL_CAMERA_DRIVER_EMSCRIPTEN 1) set(HAVE_CAMERA TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/camera/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/camera/emscripten/*.h" + ) endif() if(SDL_JOYSTICK) set(SDL_JOYSTICK_EMSCRIPTEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/joystick/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/emscripten/*.h" + ) set(HAVE_SDL_JOYSTICK TRUE) endif() if(SDL_POWER) set(SDL_POWER_EMSCRIPTEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/power/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/power/emscripten/*.h" + ) set(HAVE_SDL_POWER TRUE) endif() - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/locale/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/locale/emscripten/*.h" + ) set(HAVE_SDL_LOCALE TRUE) set(SDL_TIME_UNIX 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/time/unix/*.c" + "${SDL3_SOURCE_DIR}/src/time/unix/*.h" + ) set(HAVE_SDL_TIME TRUE) set(SDL_TIMER_UNIX 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/timer/unix/*.c" + "${SDL3_SOURCE_DIR}/src/timer/unix/*.h" + ) set(HAVE_SDL_TIMERS TRUE) if(SDL_CLOCK_GETTIME) @@ -1621,7 +1741,10 @@ elseif(EMSCRIPTEN) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_EMSCRIPTEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/emscripten/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/emscripten/*.c" + "${SDL3_SOURCE_DIR}/src/video/emscripten/*.h" + ) set(HAVE_SDL_VIDEO TRUE) #enable gles @@ -1639,11 +1762,17 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) if(SDL_AUDIO) if(NETBSD) set(SDL_AUDIO_DRIVER_NETBSD 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/netbsd/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/netbsd/*.c" + "${SDL3_SOURCE_DIR}/src/audio/netbsd/*.h" + ) set(HAVE_SDL_AUDIO TRUE) elseif(QNX) set(SDL_AUDIO_DRIVER_QNX 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/qnx/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/qnx/*.c" + "${SDL3_SOURCE_DIR}/src/audio/qnx/*.h" + ) sdl_link_dependency(asound LIBS asound) set(HAVE_SDL_AUDIO TRUE) endif() @@ -1673,12 +1802,18 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) CheckVulkan() CheckQNXScreen() - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/unix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/tray/unix/*.c" + "${SDL3_SOURCE_DIR}/src/tray/unix/*.h" + ) set(HAVE_SDL_TRAY TRUE) endif() if(UNIX) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/unix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/core/unix/*.c" + "${SDL3_SOURCE_DIR}/src/core/unix/*.h" + ) check_c_source_compiles(" #include @@ -1727,7 +1862,10 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) if(SDL_CAMERA AND HAVE_LINUX_VIDEODEV2_H) set(SDL_CAMERA_DRIVER_V4L2 1) set(HAVE_CAMERA TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/v4l2/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/camera/v4l2/*.c" + "${SDL3_SOURCE_DIR}/src/camera/v4l2/*.h" + ) endif() if(HAVE_LINUX_INPUT_H) @@ -1736,7 +1874,10 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) if(SDL_HAPTIC AND HAVE_LINUX_INPUT_H) set(SDL_HAPTIC_LINUX 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/linux/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/haptic/linux/*.c" + "${SDL3_SOURCE_DIR}/src/haptic/linux/*.h" + ) set(HAVE_SDL_HAPTIC TRUE) endif() @@ -1812,25 +1953,40 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) if(HAVE_DBUS_DBUS_H) sdl_sources( "${SDL3_SOURCE_DIR}/src/core/linux/SDL_dbus.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_dbus.h" "${SDL3_SOURCE_DIR}/src/core/linux/SDL_system_theme.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_system_theme.h" "${SDL3_SOURCE_DIR}/src/core/linux/SDL_progressbar.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_progressbar.h" ) endif() if(SDL_USE_IME) - sdl_sources("${SDL3_SOURCE_DIR}/src/core/linux/SDL_ime.c") + sdl_sources( + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_ime.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_ime.h" + ) endif() if(HAVE_IBUS_IBUS_H) - sdl_sources("${SDL3_SOURCE_DIR}/src/core/linux/SDL_ibus.c") + sdl_sources( + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_ibus.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_ibus.h" + ) endif() if(HAVE_FCITX) - sdl_sources("${SDL3_SOURCE_DIR}/src/core/linux/SDL_fcitx.c") + sdl_sources( + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_fcitx.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_fcitx.h" + ) endif() if(HAVE_LIBUDEV_H) - sdl_sources("${SDL3_SOURCE_DIR}/src/core/linux/SDL_udev.c") + sdl_sources( + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_udev.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_udev.h" + ) endif() if(HAVE_LINUX_INPUT_H) @@ -1841,13 +1997,17 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) endif() if(HAVE_INPUT_KBIO) - sdl_sources("${SDL3_SOURCE_DIR}/src/core/freebsd/SDL_evdev_kbd_freebsd.c") + sdl_sources( + "${SDL3_SOURCE_DIR}/src/core/freebsd/SDL_evdev_kbd_freebsd.c" + "${SDL3_SOURCE_DIR}/src/core/freebsd/SDL_evdev_kbd_default_keyaccmap.h" + ) endif() if(HAVE_INPUT_WSCONS) sdl_sources( "${SDL3_SOURCE_DIR}/src/core/openbsd/SDL_wscons_kbd.c" "${SDL3_SOURCE_DIR}/src/core/openbsd/SDL_wscons_mouse.c" + "${SDL3_SOURCE_DIR}/src/core/openbsd/SDL_wscons.h" ) endif() @@ -1868,6 +2028,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) # Always compiled for Linux, unconditionally: sdl_sources( "${SDL3_SOURCE_DIR}/src/core/linux/SDL_evdev_capabilities.c" + "${SDL3_SOURCE_DIR}/src/core/linux/SDL_evdev_capabilities.h" "${SDL3_SOURCE_DIR}/src/core/linux/SDL_threadprio.c" ) @@ -1886,6 +2047,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) set(SDL_JOYSTICK_LINUX 1) sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/joystick/linux/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/linux/*.h" ) set(HAVE_SDL_JOYSTICK TRUE) endif() @@ -1928,7 +2090,10 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/generic/*.c") if(LINUX) set(SDL_STORAGE_STEAM 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/steam/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/storage/steam/*.c" + "${SDL3_SOURCE_DIR}/src/storage/steam/*.h" + ) endif() set(HAVE_SDL_STORAGE 1) @@ -1976,8 +2141,11 @@ elseif(WINDOWS) #include int main(int argc, char **argv) { return 0; }" HAVE_WIN32_CC) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/windows/*.c") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/windows/*.cpp") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/core/windows/*.c" + "${SDL3_SOURCE_DIR}/src/core/windows/*.cpp" + "${SDL3_SOURCE_DIR}/src/core/windows/*.h" + ) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/windows/*.c") sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/windows/*.c") @@ -2072,22 +2240,31 @@ elseif(WINDOWS) if(SDL_AUDIO) if(HAVE_DSOUND_H) set(SDL_AUDIO_DRIVER_DSOUND 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/directsound/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/directsound/*.c" + "${SDL3_SOURCE_DIR}/src/audio/directsound/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() if(SDL_WASAPI AND HAVE_AUDIOCLIENT_H AND HAVE_MMDEVICEAPI_H) set(SDL_AUDIO_DRIVER_WASAPI 1) set(HAVE_WASAPI TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/wasapi/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/wasapi/*.c" + "${SDL3_SOURCE_DIR}/src/audio/wasapi/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() endif() if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_WINDOWS 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/windows/*.c") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/windows/*.cpp") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/windows/*.c" + "${SDL3_SOURCE_DIR}/src/video/windows/*.cpp" + "${SDL3_SOURCE_DIR}/src/video/windows/*.h" + ) CheckOpenVR() @@ -2111,7 +2288,9 @@ elseif(WINDOWS) set(SDL_THREAD_WINDOWS 1) sdl_sources( "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock_c.h" "${SDL3_SOURCE_DIR}/src/thread/windows/SDL_syscond_cv.c" "${SDL3_SOURCE_DIR}/src/thread/windows/SDL_sysmutex.c" "${SDL3_SOURCE_DIR}/src/thread/windows/SDL_sysrwlock_srw.c" @@ -2125,7 +2304,10 @@ elseif(WINDOWS) if(SDL_SENSOR AND HAVE_SENSORSAPI_H) set(SDL_SENSOR_WINDOWS 1) set(HAVE_SDL_SENSORS TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/windows/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/sensor/windows/*.c" + "${SDL3_SOURCE_DIR}/src/sensor/windows/*.h" + ) endif() if(SDL_POWER) @@ -2147,7 +2329,10 @@ elseif(WINDOWS) set(SDL_STORAGE_GENERIC 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/generic/*.c") set(SDL_STORAGE_STEAM 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/steam/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/storage/steam/*.c" + "${SDL3_SOURCE_DIR}/src/storage/steam/*.h" + ) set(HAVE_SDL_STORAGE 1) # Libraries for Win32 native and MinGW @@ -2165,7 +2350,10 @@ elseif(WINDOWS) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/windows/*.c") set(HAVE_SDL_LOADSO TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/windows/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/core/windows/*.c" + "${SDL3_SOURCE_DIR}/src/core/windows/*.h" + ) if(SDL_VIDEO) if(SDL_OPENGL) @@ -2200,7 +2388,10 @@ elseif(WINDOWS) endif() if(SDL_JOYSTICK) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/windows/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/joystick/windows/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/windows/*.h" + ) set(SDL_JOYSTICK_RAWINPUT 1) if(HAVE_DINPUT_H) @@ -2222,7 +2413,10 @@ elseif(WINDOWS) if(SDL_HAPTIC) if(HAVE_DINPUT_H) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/windows/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/haptic/windows/*.c" + "${SDL3_SOURCE_DIR}/src/haptic/windows/*.h" + ) set(SDL_HAPTIC_DINPUT 1) set(HAVE_SDL_HAPTIC TRUE) endif() @@ -2284,7 +2478,10 @@ elseif(APPLE) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_COREAUDIO 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/coreaudio/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/coreaudio/*.m" + "${SDL3_SOURCE_DIR}/src/audio/coreaudio/*.h" + ) set(HAVE_SDL_AUDIO TRUE) set(SDL_FRAMEWORK_COREAUDIO 1) set(SDL_FRAMEWORK_AUDIOTOOLBOX 1) @@ -2296,7 +2493,10 @@ elseif(APPLE) endif() if(SDL_JOYSTICK) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/apple/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/joystick/apple/*.m" + "${SDL3_SOURCE_DIR}/src/joystick/apple/*.h" + ) if(IOS OR TVOS OR VISIONOS OR WATCHOS) set(SDL_JOYSTICK_MFI 1) if(IOS OR VISIONOS OR WATCHOS) @@ -2305,7 +2505,10 @@ elseif(APPLE) set(SDL_FRAMEWORK_GAMECONTROLLER 1) set(SDL_FRAMEWORK_COREHAPTICS 1) else() - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/darwin/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/joystick/darwin/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/darwin/*.h" + ) set_property(SOURCE ${MFI_JOYSTICK_SOURCES} APPEND_STRING PROPERTY COMPILE_FLAGS " -fobjc-weak") check_objc_source_compiles(" #include @@ -2345,7 +2548,10 @@ elseif(APPLE) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/dummy/*.c") set(SDL_HAPTIC_DUMMY 1) else() - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/darwin/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/haptic/darwin/*.c" + "${SDL3_SOURCE_DIR}/src/haptic/darwin/*.h" + ) set(SDL_HAPTIC_IOKIT 1) set(SDL_FRAMEWORK_IOKIT 1) set(SDL_FRAMEWORK_FF 1) @@ -2355,7 +2561,10 @@ elseif(APPLE) if(SDL_POWER) if (IOS OR TVOS OR VISIONOS OR WATCHOS) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/uikit/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/power/uikit/*.m" + "${SDL3_SOURCE_DIR}/src/power/uikit/*.h" + ) set(SDL_POWER_UIKIT 1) else() sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/macos/*.c") @@ -2385,7 +2594,10 @@ elseif(APPLE) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/generic/*.c") if(MACOS) set(SDL_STORAGE_STEAM 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/steam/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/storage/steam/*.c" + "${SDL3_SOURCE_DIR}/src/storage/steam/*.h" + ) endif() set(HAVE_SDL_STORAGE 1) @@ -2397,7 +2609,10 @@ elseif(APPLE) if(IOS OR VISIONOS OR WATCHOS) set(SDL_SENSOR_COREMOTION 1) set(HAVE_SDL_SENSORS TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/coremotion/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/sensor/coremotion/*.m" + "${SDL3_SOURCE_DIR}/src/sensor/coremotion/*.h" + ) endif() endif() @@ -2410,7 +2625,10 @@ elseif(APPLE) set(SDL_FRAMEWORK_UIKIT 1) set(SDL_IPHONE_KEYBOARD 1) set(SDL_IPHONE_LAUNCHSCREEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/uikit/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/uikit/*.m" + "${SDL3_SOURCE_DIR}/src/video/uikit/*.h" + ) set(HAVE_SDL_VIDEO TRUE) else() CheckCOCOA() @@ -2460,13 +2678,19 @@ elseif(APPLE) set(HAVE_METAL TRUE) endif() if(SDL_RENDER_METAL) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/metal/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/render/metal/*.m" + "${SDL3_SOURCE_DIR}/src/render/metal/*.h" + ) set(SDL_VIDEO_RENDER_METAL 1) set(HAVE_RENDER_METAL TRUE) endif() if (SDL_GPU) set(SDL_GPU_METAL 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/metal/*.m") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/gpu/metal/*.m" + "${SDL3_SOURCE_DIR}/src/gpu/metal/*.h" + ) endif() endif() endif() @@ -2560,7 +2784,10 @@ elseif(HAIKU) enable_language(CXX) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_HAIKU 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/haiku/*.cc") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/haiku/*.cc" + "${SDL3_SOURCE_DIR}/src/audio/haiku/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() @@ -2575,7 +2802,10 @@ elseif(HAIKU) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_HAIKU 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/haiku/*.cc") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/haiku/*.cc" + "${SDL3_SOURCE_DIR}/src/video/haiku/*.h" + ) set(HAVE_SDL_VIDEO TRUE) if(SDL_OPENGL) @@ -2613,7 +2843,10 @@ elseif(HAIKU) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/haiku/*.cc") set(HAVE_SDL_LOCALE TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/haiku/*.cc") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/core/haiku/*.cc" + "${SDL3_SOURCE_DIR}/src/core/haiku/*.h" + ) CheckPTHREAD() sdl_link_dependency(base LIBS root be media game device textencoding tracker) @@ -2624,7 +2857,10 @@ elseif(RISCOS) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_RISCOS 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/riscos/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/riscos/*.c" + "${SDL3_SOURCE_DIR}/src/video/riscos/*.h" + ) set(HAVE_SDL_VIDEO TRUE) endif() @@ -2664,12 +2900,17 @@ elseif(VITA) set_property(SOURCE "${SDL3_SOURCE_DIR}/src/atomic/SDL_spinlock.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -marm") endif() - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/vita/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/misc/vita/*.c" + ) set(HAVE_SDL_MISC TRUE) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_VITA 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/vita/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/vita/*.c" + "${SDL3_SOURCE_DIR}/src/audio/vita/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() @@ -2696,10 +2937,14 @@ elseif(VITA) set(SDL_THREAD_VITA 1) sdl_sources( "${SDL3_SOURCE_DIR}/src/thread/vita/SDL_sysmutex.c" + "${SDL3_SOURCE_DIR}/src/thread/vita/SDL_sysmutex_c.h" "${SDL3_SOURCE_DIR}/src/thread/vita/SDL_syssem.c" "${SDL3_SOURCE_DIR}/src/thread/vita/SDL_systhread.c" + "${SDL3_SOURCE_DIR}/src/thread/vita/SDL_systhread_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c" ) set(HAVE_SDL_THREADS TRUE) @@ -2718,7 +2963,10 @@ elseif(VITA) if(SDL_SENSOR) set(SDL_SENSOR_VITA 1) set(HAVE_SDL_SENSORS TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/vita/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/sensor/vita/*.c" + "${SDL3_SOURCE_DIR}/src/sensor/vita/*.h" + ) endif() if(SDL_CAMERA) @@ -2729,7 +2977,10 @@ elseif(VITA) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_VITA 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/vita/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/vita/*.c" + "${SDL3_SOURCE_DIR}/src/video/vita/*.h" + ) set(HAVE_SDL_VIDEO TRUE) if(VIDEO_VITA_PIB) @@ -2818,7 +3069,10 @@ elseif(PSP) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_PSP 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/psp/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/psp/*.c" + "${SDL3_SOURCE_DIR}/src/audio/psp/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() @@ -2845,9 +3099,12 @@ elseif(PSP) set(SDL_THREAD_PSP 1) sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock_c.h" "${SDL3_SOURCE_DIR}/src/thread/psp/*.c" + "${SDL3_SOURCE_DIR}/src/thread/psp/*.h" ) set(HAVE_SDL_THREADS TRUE) @@ -2865,7 +3122,10 @@ elseif(PSP) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_PSP 1) set(SDL_VIDEO_RENDER_PSP 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/psp/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/psp/*.c" + "${SDL3_SOURCE_DIR}/src/video/psp/*.h" + ) set(SDL_VIDEO_OPENGL 1) set(HAVE_SDL_VIDEO TRUE) endif() @@ -2889,7 +3149,10 @@ elseif(PS2) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_PS2 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ps2/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/ps2/*.c" + "${SDL3_SOURCE_DIR}/src/audio/ps2/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() @@ -2910,10 +3173,13 @@ elseif(PS2) set(SDL_THREAD_PS2 1) sdl_glob_sources( "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysmutex.c" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c" "${SDL3_SOURCE_DIR}/src/thread/ps2/*.c" + "${SDL3_SOURCE_DIR}/src/thread/ps2/*.h" ) set(HAVE_SDL_THREADS TRUE) @@ -2948,7 +3214,10 @@ elseif(N3DS) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_N3DS 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/n3ds/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/n3ds/*.c" + "${SDL3_SOURCE_DIR}/src/audio/n3ds/*.h" + ) set(HAVE_SDL_AUDIO TRUE) endif() @@ -2971,11 +3240,16 @@ elseif(N3DS) endif() set(SDL_THREAD_N3DS 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/thread/n3ds/*.c" + "${SDL3_SOURCE_DIR}/src/thread/n3ds/*.h" + ) sdl_sources( "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syscond_c.h" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_systls.c" "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_sysrwlock_c.h" ) set(HAVE_SDL_THREADS TRUE) @@ -2999,29 +3273,45 @@ elseif(N3DS) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_N3DS 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/n3ds/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/n3ds/*.c" + "${SDL3_SOURCE_DIR}/src/video/n3ds/*.h" + ) set(HAVE_SDL_VIDEO TRUE) endif() sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/n3ds/*.c") set(HAVE_SDL_LOCALE TRUE) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/n3ds/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/io/n3ds/*.c" + "${SDL3_SOURCE_DIR}/src/io/n3ds/*.h" + ) elseif(NGAGE) enable_language(CXX) set(SDL_MAIN_USE_CALLBACKS 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/ngage/*.c") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/ngage/*.cpp") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ngage/*.cpp") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/main/ngage/*.c" + "${SDL3_SOURCE_DIR}/src/main/ngage/*.cpp" + "${SDL3_SOURCE_DIR}/src/main/ngage/*.hpp" + ) + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/core/ngage/*.cpp" + "${SDL3_SOURCE_DIR}/src/core/ngage/*.h" + ) set(HAVE_SDL_MAIN_CALLBACKS TRUE) if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_NGAGE 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ngage/*.c") - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ngage/*.cpp") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/ngage/*.c" + "${SDL3_SOURCE_DIR}/src/audio/ngage/*.cpp" + "${SDL3_SOURCE_DIR}/src/audio/ngage/*.h" + "${SDL3_SOURCE_DIR}/src/audio/ngage/*.hpp" + ) set(HAVE_SDL_AUDIO TRUE) endif() @@ -3035,13 +3325,20 @@ elseif(NGAGE) if(SDL_RENDER) set(SDL_VIDEO_RENDER_NGAGE 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/ngage/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/render/ngage/*.c" + "${SDL3_SOURCE_DIR}/src/render/ngage/*.h" + "${SDL3_SOURCE_DIR}/src/render/ngage/*.hpp" + ) endif() sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/ngage/*.cpp") set(SDL_TIME_NGAGE 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/ngage/*.cpp") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/render/ngage/*.cpp" + "${SDL3_SOURCE_DIR}/src/render/ngage/*.h" + ) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c") set(SDL_TIMER_NGAGE 1) @@ -3050,7 +3347,10 @@ elseif(NGAGE) set(SDL_FSOPS_POSIX 1) set(SDL_VIDEO_DRIVER_NGAGE 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/ngage/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/ngage/*.c" + "${SDL3_SOURCE_DIR}/src/video/ngage/*.h" + ) set(HAVE_SDL_TIMERS TRUE) set_option(SDL_LEAN_AND_MEAN "Enable lean and mean" ON) @@ -3093,7 +3393,9 @@ if (SDL_DIALOG) elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_unixdialog.c) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_portaldialog.c) + sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_portaldialog.h) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_zenitydialog.c) + sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_zenitydialog.h) set(HAVE_SDL_DIALOG TRUE) elseif(HAIKU) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/haiku/SDL_haikudialog.cc) @@ -3109,7 +3411,10 @@ endif() sdl_sources("${SDL3_SOURCE_DIR}/src/process/SDL_process.c") if(WINDOWS) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/process/windows/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/process/windows/*.c" + "${SDL3_SOURCE_DIR}/src/process/windows/*.h" + ) set(SDL_PROCESS_WINDOWS 1) set(HAVE_SDL_PROCESS TRUE) else() @@ -3150,7 +3455,10 @@ int main(void) } " HAVE_POSIX_SPAWN) if(HAVE_POSIX_SPAWN) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/process/posix/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/process/posix/*.c" + "${SDL3_SOURCE_DIR}/src/process/posix/*.h" + ) set(SDL_PROCESS_POSIX 1) set(HAVE_SDL_PROCESS TRUE) endif() @@ -3161,7 +3469,10 @@ endif() if(SDL_VIDEO) if(SDL_OFFSCREEN) set(SDL_VIDEO_DRIVER_OFFSCREEN 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/offscreen/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/offscreen/*.c" + "${SDL3_SOURCE_DIR}/src/video/offscreen/*.h" + ) set(HAVE_OFFSCREEN TRUE) set(HAVE_SDL_VIDEO TRUE) endif() @@ -3171,17 +3482,26 @@ sdl_glob_sources(${SDL3_SOURCE_DIR}/src/tray/*.c) if(SDL_GPU) if(HAVE_D3D11_H) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d11/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/gpu/d3d11/*.c" + "${SDL3_SOURCE_DIR}/src/gpu/d3d11/*.h" + ) set(SDL_GPU_D3D11 1) set(HAVE_SDL_GPU TRUE) endif() if(WINDOWS) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c" + "${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.h" + ) set(SDL_GPU_D3D12 1) set(HAVE_SDL_GPU TRUE) endif() if(SDL_VIDEO_VULKAN) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/vulkan/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/gpu/vulkan/*.c" + "${SDL3_SOURCE_DIR}/src/gpu/vulkan/*.h" + ) set(SDL_GPU_VULKAN 1) set(HAVE_SDL_GPU TRUE) endif() @@ -3201,35 +3521,59 @@ endif() # src/X/*.c does not get included. if(NOT HAVE_SDL_AUDIO) set(SDL_AUDIO_DRIVER_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/audio/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/audio/dummy/*.h" + ) endif() if(NOT HAVE_SDL_VIDEO) set(SDL_VIDEO_DRIVER_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/video/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/video/dummy/*.h" + ) endif() if(NOT HAVE_SDL_JOYSTICK) set(SDL_JOYSTICK_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/joystick/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/joystick/dummy/*.h" + ) endif() if(NOT HAVE_SDL_HAPTIC) set(SDL_HAPTIC_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/haptic/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/haptic/dummy/*.h" + ) endif() if(NOT HAVE_SDL_SENSORS) set(SDL_SENSOR_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/sensor/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/sensor/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/sensor/dummy/*.h" + ) endif() if(NOT HAVE_SDL_LOADSO) set(SDL_LOADSO_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/loadso/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/loadso/dummy/*.h" + ) endif() if(NOT HAVE_SDL_FILESYSTEM) set(SDL_FILESYSTEM_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/filesystem/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/filesystem/dummy/*.h" + ) endif() if(NOT HAVE_SDL_STORAGE) set(SDL_STORAGE_GENERIC 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/storage/generic/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/storage/generic/*.c" + "${SDL3_SOURCE_DIR}/src/storage/generic/*.h" + ) endif() if(NOT HAVE_SDL_FSOPS) set(SDL_FSOPS_DUMMY 1) @@ -3237,11 +3581,17 @@ if(NOT HAVE_SDL_FSOPS) endif() if(NOT HAVE_SDL_LOCALE) set(SDL_LOCALE_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/locale/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/locale/dummy/*.h" + ) endif() if(NOT HAVE_SDL_MISC) set(SDL_MISC_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/misc/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/misc/dummy/*.h" + ) endif() if(NOT HAVE_SDL_DIALOG) set(SDL_DIALOG_DUMMY 1) @@ -3257,7 +3607,10 @@ if(NOT HAVE_SDL_TRAY) endif() if(NOT HAVE_CAMERA) set(SDL_CAMERA_DRIVER_DUMMY 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/camera/dummy/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/camera/dummy/*.c" + "${SDL3_SOURCE_DIR}/src/camera/dummy/*.h" + ) endif() # We always need to have threads and timers around @@ -3265,7 +3618,10 @@ if(NOT HAVE_SDL_THREADS) # The Emscripten and N-Gage platform has been carefully vetted to work without threads if(EMSCRIPTEN OR NGAGE) set(SDL_THREADS_DISABLED 1) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/generic/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/thread/generic/*.c" + "${SDL3_SOURCE_DIR}/src/thread/generic/*.h" + ) else() message(FATAL_ERROR "Threads are needed by many SDL subsystems and may not be disabled") endif() @@ -3276,7 +3632,10 @@ endif() # Most platforms use this. if(NOT HAVE_SDL_MAIN_CALLBACKS) - sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/generic/*.c") + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/main/generic/*.c" + "${SDL3_SOURCE_DIR}/src/main/generic/*.h" + ) endif() # config variables may contain generator expression, so we need to generate SDL_build_config.h in 2 steps: @@ -3319,9 +3678,10 @@ list(APPEND SDL3_INCLUDE_FILES "${SDL3_BINARY_DIR}/include-revision/SDL3/SDL_rev if(SDL_FRAMEWORK) # With Apple frameworks, headers in the PUBLIC_HEADER property also need to be added as sources list(APPEND SDL3_INCLUDE_FILES ${SDL3_TEST_INCLUDE_FILES}) - sdl_sources(${SDL3_INCLUDE_FILES}) endif() +sdl_sources(${SDL3_INCLUDE_FILES}) + if((CMAKE_STATIC_LIBRARY_PREFIX STREQUAL "" AND CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL ".lib") OR SDL_FRAMEWORK) # - Avoid conflict between the dll import library and the static library # - Create SDL3-static Apple Framework diff --git a/android-project/app/build.gradle b/android-project/app/build.gradle index f44cf26732..989ef34c71 100644 --- a/android-project/app/build.gradle +++ b/android-project/app/build.gradle @@ -19,7 +19,7 @@ android { abiFilters 'arm64-v8a' } cmake { - arguments "-DANDROID_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DAPP_SUPPORT_FLEXIBLE_PAGE_SIZES=true" + arguments "-DANDROID_PLATFORM=android-21", "-DANDROID_STL=c++_static" // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' abiFilters 'arm64-v8a' } diff --git a/android-project/app/jni/Application.mk b/android-project/app/jni/Application.mk index 80b73fd6bc..1f7c0c10f9 100644 --- a/android-project/app/jni/Application.mk +++ b/android-project/app/jni/Application.mk @@ -8,6 +8,3 @@ APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 # Min runtime API level APP_PLATFORM=android-21 - -# https://developer.android.com/guide/practices/page-sizes#update-packaging -APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true \ No newline at end of file diff --git a/android-project/app/jni/src/CMakeLists.txt b/android-project/app/jni/src/CMakeLists.txt index df0a4d0f34..41a82f2af0 100644 --- a/android-project/app/jni/src/CMakeLists.txt +++ b/android-project/app/jni/src/CMakeLists.txt @@ -26,9 +26,4 @@ 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) diff --git a/build-scripts/androidbuildlibs.sh b/build-scripts/androidbuildlibs.sh index 1004a98703..a903f36eea 100755 --- a/build-scripts/androidbuildlibs.sh +++ b/build-scripts/androidbuildlibs.sh @@ -30,7 +30,6 @@ 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 @@ -43,8 +42,6 @@ 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 @@ -70,9 +67,6 @@ 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 \ @@ -81,5 +75,4 @@ ndk-build \ APP_ABI="$abi" \ APP_PLATFORM="$platform" \ APP_MODULES="SDL3" \ - APP_SUPPORT_FLEXIBLE_PAGE_SIZES="$flexpage" \ $ndk_args diff --git a/build-scripts/build-release.py b/build-scripts/build-release.py index c00743e97b..e25bda8c11 100755 --- a/build-scripts/build-release.py +++ b/build-scripts/build-release.py @@ -542,6 +542,7 @@ class AndroidApiVersion: def __repr__(self) -> str: return f"<{self.name} ({'.'.join(str(v) for v in self.ints)})>" +ANDROID_ABI_EXTRA_LINK_OPTIONS = {} class Releaser: def __init__(self, release_info: dict, commit: str, revision: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str, deps_path: Path, overwrite: bool, github: bool, fast: bool): @@ -1013,6 +1014,7 @@ class Releaser: android_devel_file_tree = ArchiveFileTree() for android_abi in android_abis: + extra_link_options = ANDROID_ABI_EXTRA_LINK_OPTIONS.get(android_abi, "") with self.section_printer.group(f"Building for Android {android_api} {android_abi}"): build_dir = self.root / "build-android" / f"{android_abi}-build" install_dir = self.root / "install-android" / f"{android_abi}-install" @@ -1026,6 +1028,8 @@ class Releaser: # NDK 21e does not support -ffile-prefix-map # f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''', # f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''', + f"-DCMAKE_EXE_LINKER_FLAGS={extra_link_options}", + f"-DCMAKE_SHARED_LINKER_FLAGS={extra_link_options}", f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}", f"-DCMAKE_PREFIX_PATH={str(android_deps_path)}", f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH", diff --git a/build-scripts/release-info.json b/build-scripts/release-info.json index 8ba213ae27..4847751414 100644 --- a/build-scripts/release-info.json +++ b/build-scripts/release-info.json @@ -183,7 +183,7 @@ ], "api-minimum": 21, "api-target": 35, - "ndk-minimum": 21, + "ndk-minimum": 28, "aar-files": { "": [ "android-project/app/proguard-rules.pro:proguard.txt", diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index a73150c95c..3100fb3d41 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -390,7 +390,7 @@ macro(CheckX11) set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1) endif() - check_symbol_exists(XkbLookupKeySym "X11/Xlib.h;X11/XKBlib.h" SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM) + check_include_file("X11/XKBlib.h" SDL_VIDEO_DRIVER_X11_HAS_XKBLIB) if(SDL_X11_XCURSOR AND HAVE_XCURSOR_H AND XCURSOR_LIB) set(HAVE_X11_XCURSOR TRUE) @@ -416,6 +416,17 @@ macro(CheckX11) endif() set(SDL_VIDEO_DRIVER_X11_XINPUT2 1) + # Check for scroll info + check_c_source_compiles(" + #include + #include + #include + XIScrollClassInfo *s; + int main(int argc, char **argv) {}" HAVE_XINPUT2_SCROLLINFO) + if(HAVE_XINPUT2_SCROLLINFO) + set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO 1) + endif() + # Check for multitouch check_c_source_compiles_static(" #include @@ -873,6 +884,9 @@ macro(CheckPTHREAD) set(PTHREAD_LDFLAGS "-pthread") elseif(QNX) # pthread support is baked in + elseif(HURD) + set(PTHREAD_CFLAGS "-D_REENTRANT") + set(PTHREAD_LDFLAGS "-pthread") else() set(PTHREAD_CFLAGS "-D_REENTRANT") set(PTHREAD_LDFLAGS "-lpthread") diff --git a/cmake/sdlcommands.cmake b/cmake/sdlcommands.cmake index d658eb3f8e..1349326313 100644 --- a/cmake/sdlcommands.cmake +++ b/cmake/sdlcommands.cmake @@ -1,6 +1,21 @@ add_library(SDL3-collector INTERFACE) add_library(SDL3_test-collector INTERFACE) +function(sdl_source_group prefix_directory) + set(prefixed_list) + file(TO_CMAKE_PATH ${prefix_directory} normalized_prefix_path) + foreach(file in ${ARGN}) + file(TO_CMAKE_PATH ${file} normalized_path) + string(FIND "${normalized_path}" ${normalized_prefix_path} position) + if("${position}" EQUAL 0) + list(APPEND prefixed_list ${file}) + endif() + endforeach() + if(prefixed_list) + source_group(TREE ${prefix_directory} FILES ${prefixed_list}) + endif() +endfunction() + # Use sdl_glob_sources to add glob sources to SDL3-shared, to SDL3-static, or to both. function(sdl_glob_sources) cmake_parse_arguments(ARGS "" "" "SHARED;STATIC" ${ARGN}) @@ -13,6 +28,7 @@ function(sdl_glob_sources) if(TARGET SDL3-static) target_sources(SDL3-static PRIVATE ${static_sources} ${both_sources}) endif() + sdl_source_group(${PROJECT_SOURCE_DIR} ${shared_sources} ${shared_sources} ${both_sources}) set_property(TARGET SDL3-collector APPEND PROPERTY INTERFACE_SOURCES ${shared_sources} ${static_sources} ${both_sources}) endfunction() @@ -25,6 +41,7 @@ function(sdl_sources) if(TARGET SDL3-static) target_sources(SDL3-static PRIVATE ${ARGS_STATIC} ${ARGS_UNPARSED_ARGUMENTS}) endif() + sdl_source_group(${PROJECT_SOURCE_DIR} ${ARGS_SHARED} ${ARGS_STATIC} ${ARGS_UNPARSED_ARGUMENTS}) set_property(TARGET SDL3-collector APPEND PROPERTY INTERFACE_SOURCES ${ARGS_SHARED} ${ARGS_STATIC} ${ARGS_UNPARSED_ARGUMENTS}) endfunction() diff --git a/cmake/sdlplatform.cmake b/cmake/sdlplatform.cmake index 60e0e77fd9..f16fe3f2ef 100644 --- a/cmake/sdlplatform.cmake +++ b/cmake/sdlplatform.cmake @@ -26,6 +26,8 @@ function(SDL_DetectCMakePlatform) set(sdl_cmake_platform ngage) elseif(PS2) set(sdl_cmake_platform ps2) + elseif(RISCOS) + set(sdl_cmake_platform RISCOS) elseif(VITA) set(sdl_cmake_platform Vita) elseif(CMAKE_SYSTEM_NAME MATCHES ".*Linux") @@ -36,8 +38,9 @@ function(SDL_DetectCMakePlatform) set(sdl_cmake_platform NetBSD) elseif(CMAKE_SYSTEM_NAME MATCHES "kOpenBSD.*|OpenBSD.*") set(sdl_cmake_platform OpenBSD) - elseif(CMAKE_SYSTEM_NAME MATCHES ".*GNU.*") - set(sdl_cmake_platform GNU) + elseif(CMAKE_SYSTEM_NAME STREQUAL "GNU") + # GNU/Hurd must be checked AFTER RISCOS + set(sdl_cmake_platform Hurd) elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*") set(sdl_cmake_platform BSDi) elseif(CMAKE_SYSTEM_NAME MATCHES "DragonFly.*|FreeBSD") diff --git a/include/SDL3/SDL_assert.h b/include/SDL3/SDL_assert.h index c64fcd76e7..48f17f5fb2 100644 --- a/include/SDL3/SDL_assert.h +++ b/include/SDL3/SDL_assert.h @@ -126,7 +126,7 @@ extern "C" { */ #define SDL_TriggerBreakpoint() TriggerABreakpointInAPlatformSpecificManner -#elif defined(_MSC_VER) && _MSC_VER >= 1310 +#elif defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1310) /* Don't include intrin.h here because it contains C++ code */ extern void __cdecl __debugbreak(void); #define SDL_TriggerBreakpoint() __debugbreak() diff --git a/include/SDL3/SDL_camera.h b/include/SDL3/SDL_camera.h index 5f3911fdf9..c0e2ee0fed 100644 --- a/include/SDL3/SDL_camera.h +++ b/include/SDL3/SDL_camera.h @@ -119,7 +119,7 @@ typedef struct SDL_CameraSpec int width; /**< Frame width */ int height; /**< Frame height */ int framerate_numerator; /**< Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) */ - int framerate_denominator; /**< Frame rate demoninator ((num / denom) == FPS, (denom / num) == duration in seconds) */ + int framerate_denominator; /**< Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds) */ } SDL_CameraSpec; /** diff --git a/include/SDL3/SDL_endian.h b/include/SDL3/SDL_endian.h index 2a9b8a34d8..41ad0ce51a 100644 --- a/include/SDL3/SDL_endian.h +++ b/include/SDL3/SDL_endian.h @@ -128,7 +128,7 @@ _m_prefetch(void *__P) * \sa SDL_BIG_ENDIAN */ #define SDL_BYTEORDER SDL_LIL_ENDIAN___or_maybe___SDL_BIG_ENDIAN -#elif defined(SDL_PLATFORM_LINUX) +#elif defined(SDL_PLATFORM_LINUX) || defined(__GLIBC__) #include #define SDL_BYTEORDER __BYTE_ORDER #elif defined(SDL_PLATFORM_SOLARIS) diff --git a/include/SDL3/SDL_filesystem.h b/include/SDL3/SDL_filesystem.h index e428258218..dd9430a819 100644 --- a/include/SDL3/SDL_filesystem.h +++ b/include/SDL3/SDL_filesystem.h @@ -89,6 +89,8 @@ extern "C" { * doesn't implement this functionality, call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetPrefPath @@ -150,6 +152,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetBasePath(void); * etc.). This should be freed with SDL_free() when it is no longer * needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetBasePath @@ -222,6 +226,8 @@ typedef enum SDL_Folder * \returns either a null-terminated C string containing the full path to the * folder, or NULL if an error happened. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC const char * SDLCALL SDL_GetUserFolder(SDL_Folder folder); @@ -289,6 +295,8 @@ typedef Uint32 SDL_GlobFlags; * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_CreateDirectory(const char *path); @@ -352,6 +360,8 @@ typedef SDL_EnumerationResult (SDLCALL *SDL_EnumerateDirectoryCallback)(void *us * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata); @@ -366,6 +376,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateDirectory(const char *path, SDL_En * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path); @@ -373,7 +385,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path); /** * Rename a file or directory. * - * If the file at `newpath` already exists, it will replaced. + * If the file at `newpath` already exists, it will be replaced. * * Note that this will not copy files across filesystems/drives/volumes, as * that is a much more complicated (and possibly time-consuming) operation. @@ -389,6 +401,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_RenamePath(const char *oldpath, const char *newpath); @@ -429,6 +443,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenamePath(const char *oldpath, const char * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread, but this + * operation is not atomic, so the app might need to protect + * access to specific paths from other threads if appropriate. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_CopyFile(const char *oldpath, const char *newpath); @@ -442,6 +460,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CopyFile(const char *oldpath, const char *n * \returns true on success or false if the file doesn't exist, or another * failure; call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo *info); @@ -496,6 +516,8 @@ extern SDL_DECLSPEC char ** SDLCALL SDL_GlobDirectory(const char *path, const ch * platform-dependent notation. NULL if there's a problem. This * should be freed with SDL_free() when it is no longer needed. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC char * SDLCALL SDL_GetCurrentDirectory(void); diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h index 460ae98780..dc21d0d068 100644 --- a/include/SDL3/SDL_gamepad.h +++ b/include/SDL3/SDL_gamepad.h @@ -165,14 +165,14 @@ typedef enum SDL_GamepadButton SDL_GAMEPAD_BUTTON_DPAD_LEFT, SDL_GAMEPAD_BUTTON_DPAD_RIGHT, SDL_GAMEPAD_BUTTON_MISC1, /**< Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button, Google Stadia capture button) */ - SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, /**< Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) */ - SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, /**< Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) */ - SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2, /**< Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) */ - SDL_GAMEPAD_BUTTON_LEFT_PADDLE2, /**< Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) */ + SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, /**< Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1, DualSense Edge RB button, Right Joy-Con SR button) */ + SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, /**< Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3, DualSense Edge LB button, Left Joy-Con SL button) */ + SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2, /**< Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2, DualSense Edge right Fn button, Right Joy-Con SL button) */ + SDL_GAMEPAD_BUTTON_LEFT_PADDLE2, /**< Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4, DualSense Edge left Fn button, Left Joy-Con SR button) */ SDL_GAMEPAD_BUTTON_TOUCHPAD, /**< PS4/PS5 touchpad button */ SDL_GAMEPAD_BUTTON_MISC2, /**< Additional button */ - SDL_GAMEPAD_BUTTON_MISC3, /**< Additional button */ - SDL_GAMEPAD_BUTTON_MISC4, /**< Additional button */ + SDL_GAMEPAD_BUTTON_MISC3, /**< Additional button (e.g. Nintendo GameCube left trigger click) */ + SDL_GAMEPAD_BUTTON_MISC4, /**< Additional button (e.g. Nintendo GameCube right trigger click) */ SDL_GAMEPAD_BUTTON_MISC5, /**< Additional button */ SDL_GAMEPAD_BUTTON_MISC6, /**< Additional button */ SDL_GAMEPAD_BUTTON_COUNT diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 0e82e2b040..85e63baf6d 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -1158,7 +1158,7 @@ typedef enum SDL_GPUCompareOp SDL_GPU_COMPAREOP_LESS_OR_EQUAL, /**< The comparison evaluates reference <= test. */ SDL_GPU_COMPAREOP_GREATER, /**< The comparison evaluates reference > test. */ SDL_GPU_COMPAREOP_NOT_EQUAL, /**< The comparison evaluates reference != test. */ - SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, /**< The comparison evalutes reference >= test. */ + SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, /**< The comparison evaluates reference >= test. */ SDL_GPU_COMPAREOP_ALWAYS /**< The comparison always evaluates true. */ } SDL_GPUCompareOp; @@ -2878,7 +2878,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_InsertGPUDebugLabel( const char *text); /** - * Begins a debug group with an arbitary name. + * Begins a debug group with an arbitrary name. * * Used for denoting groups of calls when viewing the command buffer * callstream in a graphics debugging tool. diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 09c918b13a..5e202827b3 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -595,7 +595,7 @@ extern "C" { * A variable that limits what CPU features are available. * * By default, SDL marks all features the current CPU supports as available. - * This hint allows to limit these to a subset. + * This hint allows the enabled features to be limited to a subset. * * When the hint is unset, or empty, SDL will enable all detected CPU * features. diff --git a/include/SDL3/SDL_platform_defines.h b/include/SDL3/SDL_platform_defines.h index a8ebbfd7d0..d270c511c2 100644 --- a/include/SDL3/SDL_platform_defines.h +++ b/include/SDL3/SDL_platform_defines.h @@ -489,4 +489,14 @@ #define SDL_PLATFORM_NGAGE 1 #endif +#ifdef __GNU__ + +/** + * A preprocessor macro that is only defined if compiling for GNU/Hurd. + * + * \since This macro is available since SDL 3.4.0. + */ +#define SDL_PLATFORM_HURD 1 +#endif + #endif /* SDL_platform_defines_h_ */ diff --git a/include/SDL3/SDL_rect.h b/include/SDL3/SDL_rect.h index e09f92a460..5911bd3b2b 100644 --- a/include/SDL3/SDL_rect.h +++ b/include/SDL3/SDL_rect.h @@ -88,8 +88,11 @@ typedef struct SDL_Rect /** - * A rectangle, with the origin at the upper left (using floating point - * values). + * A rectangle stored using floating point values. + * + * The origin of the coordinate space is in the top-left, with increasing + * values moving down and right. The properties `x` and `y` represent the + * coordinates of the top-left corner of the rectangle. * * \since This struct is available since SDL 3.2.0. * diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 8fcc1de8a7..bfb758235f 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -2747,7 +2747,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo * Draw debug text to an SDL_Renderer. * * This function will render a printf()-style format string to a renderer. - * Note that this is a convinence function for debugging, with severe + * Note that this is a convenience function for debugging, with severe * limitations, and is not intended to be used for production apps and games. * * For the full list of limitations and other useful information, see diff --git a/include/SDL3/SDL_stdinc.h b/include/SDL3/SDL_stdinc.h index 206ff1dbf4..21266e81e4 100644 --- a/include/SDL3/SDL_stdinc.h +++ b/include/SDL3/SDL_stdinc.h @@ -3426,7 +3426,7 @@ extern SDL_DECLSPEC size_t SDLCALL SDL_utf8strnlen(const char *str, size_t bytes * Convert an integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3454,7 +3454,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_itoa(int value, char *str, int radix); * Convert an unsigned integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3482,7 +3482,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_uitoa(unsigned int value, char *str, int * Convert a long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3510,7 +3510,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_ltoa(long value, char *str, int radix); * Convert an unsigned long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3540,7 +3540,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_ultoa(unsigned long value, char *str, int * Convert a long long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3568,7 +3568,7 @@ extern SDL_DECLSPEC char * SDLCALL SDL_lltoa(long long value, char *str, int rad * Convert an unsigned long long integer into a string. * * This requires a radix to specified for string format. Specifying 10 - * produces a decimal number, 16 hexidecimal, etc. Must be in the range of 2 + * produces a decimal number, 16 hexadecimal, etc. Must be in the range of 2 * to 36. * * Note that this function will overflow a buffer if `str` is not large enough @@ -3923,7 +3923,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str extern SDL_DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen); /** - * Searches a string for the first occurence of any character contained in a + * Searches a string for the first occurrence of any character contained in a * breakset, and returns a pointer from the string to that character. * * \param str The null-terminated string to be searched. Must not be NULL, and @@ -3931,7 +3931,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_strncasecmp(const char *str1, const char *st * \param breakset A null-terminated string containing the list of characters * to look for. Must not be NULL, and must not overlap with * `str`. - * \returns A pointer to the location, in str, of the first occurence of a + * \returns A pointer to the location, in str, of the first occurrence of a * character present in the breakset, or NULL if none is found. * * \threadsafety It is safe to call this function from any thread. @@ -5821,7 +5821,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_iconv_close(SDL_iconv_t cd); * This function converts text between encodings, reading from and writing to * a buffer. * - * It returns the number of succesful conversions on success. On error, + * It returns the number of successful conversions on success. On error, * SDL_ICONV_E2BIG is returned when the output buffer is too small, or * SDL_ICONV_EILSEQ is returned when an invalid input sequence is encountered, * or SDL_ICONV_EINVAL is returned when an incomplete input sequence is diff --git a/include/SDL3/SDL_tray.h b/include/SDL3/SDL_tray.h index ec7adfcf7f..1780b0ba52 100644 --- a/include/SDL3/SDL_tray.h +++ b/include/SDL3/SDL_tray.h @@ -96,25 +96,6 @@ typedef Uint32 SDL_TrayEntryFlags; */ typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry); -/** - * Check whether or not tray icons can be created. - * - * Note that this function does not guarantee that SDL_CreateTray() will or - * will not work; you should still check SDL_CreateTray() for errors. - * - * Using tray icons require the video subsystem. - * - * \returns true if trays are available, false otherwise. - * - * \threadsafety This function should only be called on the main thread. It - * will return false if not called on the main thread. - * - * \since This function is available since SDL 3.4.0. - * - * \sa SDL_CreateTray - */ -extern SDL_DECLSPEC bool SDLCALL SDL_IsTraySupported(void); - /** * Create an icon to be placed in the operating system's tray, or equivalent. * diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index 09b55ad1c6..e78ba111df 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -1077,8 +1077,6 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count); * * - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution * - `SDL_WINDOW_OPENGL`: window usable with an OpenGL context - * - `SDL_WINDOW_OCCLUDED`: window partially or completely obscured by another - * window * - `SDL_WINDOW_HIDDEN`: window is not visible * - `SDL_WINDOW_BORDERLESS`: no window decoration * - `SDL_WINDOW_RESIZABLE`: window can be resized @@ -1106,7 +1104,8 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count); * - `SDL_WINDOW_TRANSPARENT`: window with transparent buffer * - `SDL_WINDOW_NOT_FOCUSABLE`: window should not be focusable * - * The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set. + * The SDL_Window will be shown if SDL_WINDOW_HIDDEN is not set. If hidden at + * creation time, SDL_ShowWindow() can be used to show it later. * * On Apple's macOS, you **must** set the NSHighResolutionCapable Info.plist * property to YES, otherwise you will not receive a High-DPI OpenGL canvas. @@ -1519,7 +1518,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window) * - `SDL_PROP_WINDOW_COCOA_WINDOW_POINTER`: the `(__unsafe_unretained)` * NSWindow associated with the window * - `SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER`: the NSInteger tag - * assocated with metal views on the window + * associated with metal views on the window * * On OpenVR: * diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 837c7240ad..36279b08df 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -424,13 +424,14 @@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST @SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST@ -#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM 1 +#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBLIB 1 #cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XDBE 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XFIXES 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1 +#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE 1 diff --git a/src/SDL.c b/src/SDL.c index bbefe4287a..4e93142b89 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -770,6 +770,8 @@ const char *SDL_GetPlatform(void) return "PlayStation Vita"; #elif defined(SDL_PLATFORM_3DS) return "Nintendo 3DS"; +#elif defined(SDL_PLATFORM_HURD) + return "GNU/Hurd"; #elif defined(__managarm__) return "Managarm"; #else diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m index e7d9e58a39..3a2217802f 100644 --- a/src/audio/coreaudio/SDL_coreaudio.m +++ b/src/audio/coreaudio/SDL_coreaudio.m @@ -420,7 +420,8 @@ static bool UpdateAudioSession(SDL_AudioDevice *device, bool open, bool allow_pl hint = SDL_GetHint(SDL_HINT_AUDIO_CATEGORY); if (hint) { - if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0) { + if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0 || + SDL_strcasecmp(hint, "ambient") == 0) { category = AVAudioSessionCategoryAmbient; } else if (SDL_strcasecmp(hint, "AVAudioSessionCategorySoloAmbient") == 0) { category = AVAudioSessionCategorySoloAmbient; diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 4d618a6e2b..debcdf27d6 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -732,7 +732,7 @@ static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device) if (!actual_bufattr) { result = SDL_SetError("Could not determine connected PulseAudio stream's buffer attributes"); } else { - device->buffer_size = (int) recording ? actual_bufattr->tlength : actual_bufattr->fragsize; + device->buffer_size = (int) recording ? actual_bufattr->fragsize : actual_bufattr->tlength; device->sample_frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec); } } diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 1f9093ef58..e0745a0a57 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -1080,7 +1080,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)( { const char *utfname = (*env)->GetStringUTFChars(env, name, NULL); - SDL_AddTouch((SDL_TouchID)touchId, SDL_TOUCH_DEVICE_DIRECT, utfname); + SDL_AddTouch(Android_ConvertJavaTouchID(touchId), + SDL_TOUCH_DEVICE_DIRECT, utfname); (*env)->ReleaseStringUTFChars(env, name, utfname); } @@ -1855,7 +1856,7 @@ bool Android_JNI_FileClose(void *userdata) bool Android_JNI_EnumerateAssetDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata) { - SDL_assert((*path == '\0') || (path[SDL_strlen(path) - 1] == '/')); // SDL_SYS_EnumerateDirectory() should have verified this. + SDL_assert(path != NULL); if (!asset_manager) { Internal_Android_Create_AssetManager(); diff --git a/src/core/linux/SDL_fcitx.c b/src/core/linux/SDL_fcitx.c index d7a9ed6656..66b21d0471 100644 --- a/src/core/linux/SDL_fcitx.c +++ b/src/core/linux/SDL_fcitx.c @@ -25,6 +25,7 @@ #include "SDL_fcitx.h" #include "../../video/SDL_sysvideo.h" #include "../../events/SDL_keyboard_c.h" +#include "../../core/unix/SDL_appid.h" #include "SDL_dbus.h" #ifdef SDL_VIDEO_DRIVER_X11 @@ -53,32 +54,14 @@ typedef struct FcitxClient static FcitxClient fcitx_client; -static char *GetAppName(void) +static const char *GetAppName(void) { -#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD) - char *spot; - char procfile[1024]; - char linkfile[1024]; - int linksize; - -#ifdef SDL_PLATFORM_LINUX - (void)SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid()); -#elif defined(SDL_PLATFORM_FREEBSD) - (void)SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid()); -#endif - linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1); - if (linksize > 0) { - linkfile[linksize] = '\0'; - spot = SDL_strrchr(linkfile, '/'); - if (spot) { - return SDL_strdup(spot + 1); - } else { - return SDL_strdup(linkfile); - } + const char *exe_name = SDL_GetExeName(); + if (exe_name) { + return exe_name; } -#endif // SDL_PLATFORM_LINUX || SDL_PLATFORM_FREEBSD - return SDL_strdup("SDL_App"); + return "SDL_App"; } static size_t Fcitx_GetPreeditString(SDL_DBusContext *dbus, @@ -281,7 +264,7 @@ static bool FcitxCreateInputContext(SDL_DBusContext *dbus, const char *appname, static bool FcitxClientCreateIC(FcitxClient *client) { - char *appname = GetAppName(); + const char *appname = GetAppName(); char *ic_path = NULL; SDL_DBusContext *dbus = client->dbus; @@ -290,8 +273,6 @@ static bool FcitxClientCreateIC(FcitxClient *client) ic_path = NULL; // just in case. } - SDL_free(appname); - if (ic_path) { SDL_free(client->ic_path); client->ic_path = SDL_strdup(ic_path); diff --git a/src/core/unix/SDL_appid.c b/src/core/unix/SDL_appid.c index 996e216cd5..8bf3349877 100644 --- a/src/core/unix/SDL_appid.c +++ b/src/core/unix/SDL_appid.c @@ -30,11 +30,11 @@ const char *SDL_GetExeName(void) // TODO: Use a fallback if BSD has no mounted procfs (OpenBSD has no procfs at all) if (!proc_name) { -#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD) || defined (SDL_PLATFORM_NETBSD) +#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD) || defined (SDL_PLATFORM_NETBSD) || defined(SDL_PLATFORM_HURD) static char linkfile[1024]; int linksize; -#if defined(SDL_PLATFORM_LINUX) +#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_HURD) const char *proc_path = "/proc/self/exe"; #elif defined(SDL_PLATFORM_FREEBSD) const char *proc_path = "/proc/curproc/file"; diff --git a/src/core/unix/SDL_gtk.c b/src/core/unix/SDL_gtk.c index 323b417bd4..d5ba754f67 100644 --- a/src/core/unix/SDL_gtk.c +++ b/src/core/unix/SDL_gtk.c @@ -27,7 +27,8 @@ ctx.sub.fn = (void *)SDL_LoadFunction(lib, #sym) #define SDL_GTK_SYM2(ctx, lib, sub, fn, sym) \ - if (!(ctx.sub.fn = (void *)SDL_LoadFunction(lib, #sym))) { \ + SDL_GTK_SYM2_OPTIONAL(ctx, lib, sub, fn, sym); \ + if (!ctx.sub.fn) { \ return SDL_SetError("Could not load GTK functions"); \ } @@ -114,8 +115,8 @@ static bool InitGtk(void) SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_submenu); SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_get_label); SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_label); - SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_append); - SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_insert); + SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_append); + SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_insert); SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_new_with_label); SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_get_active); SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_set_active); @@ -127,6 +128,7 @@ static bool InitGtk(void) SDL_GTK_SYM(gtk, libgdk, g, signal_connect_data); SDL_GTK_SYM(gtk, libgdk, g, mkdtemp); + SDL_GTK_SYM(gtk, libgdk, g, get_user_cache_dir); SDL_GTK_SYM(gtk, libgdk, g, object_ref); SDL_GTK_SYM(gtk, libgdk, g, object_ref_sink); SDL_GTK_SYM(gtk, libgdk, g, object_unref); diff --git a/src/core/unix/SDL_gtk.h b/src/core/unix/SDL_gtk.h index e966dac45e..73fef5a820 100644 --- a/src/core/unix/SDL_gtk.h +++ b/src/core/unix/SDL_gtk.h @@ -80,6 +80,7 @@ typedef struct SDL_GtkContext gulong (*signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, SDL_GConnectFlags connect_flags); void (*object_unref)(gpointer object); gchar *(*mkdtemp)(gchar *template); + gchar *(*get_user_cache_dir)(void); gpointer (*object_ref_sink)(gpointer object); gpointer (*object_ref)(gpointer object); void (*object_get)(gpointer object, const gchar *first_property_name, ...); @@ -117,7 +118,7 @@ typedef struct SDL_GtkContext extern bool SDL_Gtk_Init(void); extern void SDL_Gtk_Quit(void); extern SDL_GtkContext *SDL_Gtk_EnterContext(void); -extern void SDL_Gtk_ExitContext(SDL_GtkContext *gtk); +extern void SDL_Gtk_ExitContext(SDL_GtkContext *ctx); extern void SDL_UpdateGtk(void); #endif // SDL_gtk_h_ diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index fcae64bea6..c69956e8b0 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1253,7 +1253,6 @@ SDL3_0.0.0 { SDL_PutAudioStreamPlanarData; SDL_GetEventDescription; SDL_PutAudioStreamDataNoCopy; - SDL_IsTraySupported; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 8873ff4734..61eb4b956d 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1278,4 +1278,3 @@ #define SDL_PutAudioStreamPlanarData SDL_PutAudioStreamPlanarData_REAL #define SDL_GetEventDescription SDL_GetEventDescription_REAL #define SDL_PutAudioStreamDataNoCopy SDL_PutAudioStreamDataNoCopy_REAL -#define SDL_IsTraySupported SDL_IsTraySupported_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index f05ff2ff33..d1e362cdff 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1286,4 +1286,3 @@ SDL_DYNAPI_PROC(SDL_Renderer*,SDL_CreateGPURenderer,(SDL_Window *a,SDL_GPUShader SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamPlanarData,(SDL_AudioStream *a,const void * const*b,int c,int d),(a,b,c,d),return) SDL_DYNAPI_PROC(int,SDL_GetEventDescription,(const SDL_Event *a,char *b,int c),(a,b,c),return) SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamDataNoCopy,(SDL_AudioStream *a,const void *b,int c,SDL_AudioStreamDataCompleteCallback d,void *e),(a,b,c,d,e),return) -SDL_DYNAPI_PROC(bool,SDL_IsTraySupported,(void),(),return) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 19d3e37b47..c04d52b282 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -1445,7 +1445,6 @@ void SDL_PumpEventMaintenance(void) } #endif - // SDL_UpdateTrays will also pump GTK events if needed SDL_UpdateTrays(); SDL_SendPendingSignalEvents(); // in case we had a signal handler fire, etc. diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 6023c88608..bb43206024 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -266,7 +266,7 @@ void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event) !SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_SHIFT))) { keymap->french_numbers = false; break; - } + } } // Detect non-Latin keymap diff --git a/src/events/SDL_windowevents.c b/src/events/SDL_windowevents.c index 62fca28b9f..2e194781af 100644 --- a/src/events/SDL_windowevents.c +++ b/src/events/SDL_windowevents.c @@ -99,6 +99,12 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data case SDL_EVENT_WINDOW_MOVED: window->undefined_x = false; window->undefined_y = false; + /* Clear the pending display if this move was not the result of an explicit request, + * and the window is not scheduled to become fullscreen when shown. + */ + if (!window->last_position_pending && !(window->pending_flags & SDL_WINDOW_FULLSCREEN)) { + window->pending_displayID = 0; + } window->last_position_pending = false; if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { window->windowed.x = data1; diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 9b1fe3d390..a1e074802a 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -9587,6 +9587,7 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( commandBuffer->autoReleaseFence = true; + commandBuffer->swapchainRequested = false; commandBuffer->isDefrag = 0; /* Reset the command buffer here to avoid resets being called @@ -10494,11 +10495,18 @@ static bool VULKAN_Wait( VkResult result; Sint32 i; + SDL_LockMutex(renderer->submitLock); + result = renderer->vkDeviceWaitIdle(renderer->logicalDevice); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkDeviceWaitIdle, false); - - SDL_LockMutex(renderer->submitLock); + if (result != VK_SUCCESS) { + if (renderer->debugMode) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", "vkDeviceWaitIdle", VkErrorMessages(result)); + } + SDL_SetError("%s %s", "vkDeviceWaitIdle", VkErrorMessages(result)); + SDL_UnlockMutex(renderer->submitLock); + return false; + } for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { commandBuffer = renderer->submittedCommandBuffers[i]; diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c index 842f577cfa..fa49e457bd 100644 --- a/src/haptic/linux/SDL_syshaptic.c +++ b/src/haptic/linux/SDL_syshaptic.c @@ -1117,13 +1117,12 @@ bool SDL_SYS_HapticResume(SDL_Haptic *haptic) */ bool SDL_SYS_HapticStopAll(SDL_Haptic *haptic) { - int i, ret; + int i; // Linux does not support this natively so we have to loop. for (i = 0; i < haptic->neffects; i++) { if (haptic->effects[i].hweffect != NULL) { - ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]); - if (ret < 0) { + if (!SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i])) { return SDL_SetError("Haptic: Error while trying to stop all playing effects."); } } diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 123b534b2a..dca3cfcb91 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -823,7 +823,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) switch (sub_type) { default: // ProGCC Primary Mapping - SDL_strlcat(mapping_string, "a:b1,b:b0,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string)); + SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string)); break; } break; @@ -831,7 +831,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) switch (sub_type) { default: // GC Ultimate Primary Map - SDL_strlcat(mapping_string, "a:b0,b:b2,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b1,y:b3,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string)); + SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string)); break; } break; @@ -839,7 +839,7 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) switch (sub_type) { default: // Default Fully Exposed Mapping (Development Purposes) - SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b10,paddle2:b11,start:b12,back:b13,guide:b14,misc1:b15,paddle3:b16,paddle4:b17,touchpad:b18,misc2:b19,misc3:b20,misc4:b21,misc5:b22,misc6:b23", sizeof(mapping_string)); + SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,a:b0,b:b1,x:b2,y:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b10,paddle2:b11,start:b12,back:b13,guide:b14,misc1:b15,paddle3:b16,paddle4:b17,touchpad:b18,misc2:b19,misc3:b20,misc4:b21,misc5:b22,misc6:b23", sizeof(mapping_string)); break; } break; diff --git a/src/joystick/gdk/SDL_gameinputjoystick.cpp b/src/joystick/gdk/SDL_gameinputjoystick.cpp index bd1e9eaf63..7b4cc2e900 100644 --- a/src/joystick/gdk/SDL_gameinputjoystick.cpp +++ b/src/joystick/gdk/SDL_gameinputjoystick.cpp @@ -279,6 +279,12 @@ static bool GAMEINPUT_JoystickInit(void) return false; } +#if GAMEINPUT_API_VERSION >= 2 + // Allow background controller input + // SDL manages focus policy at a higher level, so we can set this unconditionally. + g_pGameInput->SetFocusPolicy(GameInputEnableBackgroundInput | GameInputEnableBackgroundGuideButton | GameInputEnableBackgroundShareButton); +#endif + hr = g_pGameInput->RegisterDeviceCallback(NULL, GameInputKindController, GameInputDeviceConnected, diff --git a/src/joystick/hidapi/SDL_hidapi_lg4ff.c b/src/joystick/hidapi/SDL_hidapi_lg4ff.c index 901911985f..683b2d0c6c 100644 --- a/src/joystick/hidapi/SDL_hidapi_lg4ff.c +++ b/src/joystick/hidapi/SDL_hidapi_lg4ff.c @@ -277,7 +277,7 @@ static bool HIDAPI_DriverLg4ff_IsSupportedDevice( return true; } // a supported native mode is found, send mode change command, then still state that we support the device - if (device != NULL && SDL_HIDAPI_DriverLg4ff_GetEnvInt("SDL_HIDAPI_LG4FF_NO_MODE_SWITCH", 0, 1, 0) == 0) { + if (device && SDL_HIDAPI_DriverLg4ff_GetEnvInt("SDL_HIDAPI_LG4FF_NO_MODE_SWITCH", 0, 1, 0) == 0) { HIDAPI_DriverLg4ff_SwitchMode(device, real_id); } return true; diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c index b48d35393b..6b366515d3 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam.c +++ b/src/joystick/hidapi/SDL_hidapi_steam.c @@ -1038,6 +1038,11 @@ static bool HIDAPI_DriverSteam_IsSupportedDevice(SDL_HIDAPI_Device *device, cons return false; } + if (!device) { + // Might be supported by this driver, enumerate and find out + return true; + } + if (device->is_bluetooth) { return true; } diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c index 69256627d7..8600c0242e 100644 --- a/src/joystick/virtual/SDL_virtualjoystick.c +++ b/src/joystick/virtual/SDL_virtualjoystick.c @@ -471,7 +471,7 @@ bool SDL_SendJoystickVirtualSensorDataInner(SDL_Joystick *joystick, SDL_SensorTy return false; } hwdata->sensor_events = sensor_events; - hwdata->max_sensor_events = hwdata->max_sensor_events; + hwdata->max_sensor_events = new_max_sensor_events; } VirtualSensorEvent *event = &hwdata->sensor_events[hwdata->num_sensor_events++]; diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 076b0dd51d..b9c15f8b34 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -3366,10 +3366,6 @@ bool SDL_SetRenderDrawBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) return SDL_InvalidParamError("blendMode"); } - if (blendMode == SDL_BLENDMODE_INVALID) { - return SDL_InvalidParamError("blendMode"); - } - if (!IsSupportedBlendMode(renderer, blendMode)) { return SDL_Unsupported(); } diff --git a/src/tray/cocoa/SDL_tray.m b/src/tray/cocoa/SDL_tray.m index d093972a2d..fd7f95517c 100644 --- a/src/tray/cocoa/SDL_tray.m +++ b/src/tray/cocoa/SDL_tray.m @@ -82,16 +82,6 @@ void SDL_UpdateTrays(void) { } -bool SDL_IsTraySupported(void) -{ - if (!SDL_IsMainThread()) { - SDL_SetError("This function should be called on the main thread"); - return false; - } - - return true; -} - SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) { if (!SDL_IsMainThread()) { diff --git a/src/tray/dummy/SDL_tray.c b/src/tray/dummy/SDL_tray.c index 3a95c6575b..766fb92584 100644 --- a/src/tray/dummy/SDL_tray.c +++ b/src/tray/dummy/SDL_tray.c @@ -29,11 +29,6 @@ void SDL_UpdateTrays(void) { } -bool SDL_IsTraySupported(void) -{ - return false; -} - SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) { SDL_Unsupported(); diff --git a/src/tray/unix/SDL_tray.c b/src/tray/unix/SDL_tray.c index 0671badda0..874df8b15d 100644 --- a/src/tray/unix/SDL_tray.c +++ b/src/tray/unix/SDL_tray.c @@ -153,15 +153,11 @@ struct SDL_TrayEntry { SDL_TrayMenu *submenu; }; -/* Template for g_mkdtemp(). The Xs will get replaced with a random - * directory name, which is created safely and atomically. */ -#define ICON_DIR_TEMPLATE "/tmp/SDL-tray-XXXXXX" - struct SDL_Tray { AppIndicator *indicator; SDL_TrayMenu *menu; - char icon_dir[sizeof(ICON_DIR_TEMPLATE)]; - char icon_path[256]; + char *icon_dir; + char *icon_path; GtkMenuShell *menu_cached; }; @@ -188,13 +184,13 @@ static bool new_tmp_filename(SDL_Tray *tray) { static int count = 0; - int would_have_written = SDL_snprintf(tray->icon_path, sizeof(tray->icon_path), "%s/%d.bmp", tray->icon_dir, count++); + int would_have_written = SDL_asprintf(&tray->icon_path, "%s/%d.bmp", tray->icon_dir, count++); - if (would_have_written > 0 && ((unsigned) would_have_written) < sizeof(tray->icon_path) - 1) { + if (would_have_written >= 0) { return true; } - tray->icon_path[0] = '\0'; + tray->icon_path = NULL; SDL_SetError("Failed to format new temporary filename"); return false; } @@ -237,25 +233,9 @@ static void DestroySDLMenu(SDL_TrayMenu *menu) void SDL_UpdateTrays(void) { - SDL_UpdateGtk(); -} - -bool SDL_IsTraySupported(void) -{ - if (!SDL_IsMainThread()) { - SDL_SetError("This function should be called on the main thread"); - return false; + if (SDL_HasActiveTrays()) { + SDL_UpdateGtk(); } - - static bool has_trays = false; - static bool has_been_detected_once = false; - - if (!has_been_detected_once) { - has_trays = init_appindicator() && SDL_Gtk_Init(); - has_been_detected_once = true; - } - - return has_trays; } SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) @@ -272,29 +252,47 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) SDL_Tray *tray = NULL; SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); if (!gtk) { - goto error; + goto tray_error; } tray = (SDL_Tray *)SDL_calloc(1, sizeof(*tray)); if (!tray) { - goto error; + goto tray_error; + } + + const gchar *cache_dir = gtk->g.get_user_cache_dir(); + if (!cache_dir) { + SDL_SetError("Cannot get user cache directory: %s", strerror(errno)); + goto tray_error; + } + + char *sdl_dir; + SDL_asprintf(&sdl_dir, "%s/SDL", cache_dir); + if (!SDL_GetPathInfo(sdl_dir, NULL)) { + if (!SDL_CreateDirectory(sdl_dir)) { + SDL_SetError("Cannot create directory for tray icon: %s", strerror(errno)); + goto sdl_dir_error; + } } /* On success, g_mkdtemp edits its argument in-place to replace the Xs * with a random directory name, which it creates safely and atomically. * On failure, it sets errno. */ - SDL_strlcpy(tray->icon_dir, ICON_DIR_TEMPLATE, sizeof(tray->icon_dir)); + SDL_asprintf(&tray->icon_dir, "%s/tray-XXXXXX", sdl_dir); if (!gtk->g.mkdtemp(tray->icon_dir)) { SDL_SetError("Cannot create directory for tray icon: %s", strerror(errno)); - goto error; + goto icon_dir_error; } if (icon) { if (!new_tmp_filename(tray)) { - goto error; + goto icon_dir_error; } SDL_SaveBMP(icon, tray->icon_path); + } else { + // allocate a dummy icon path + SDL_asprintf(&tray->icon_path, " "); } tray->indicator = app_indicator_new(get_appindicator_id(), tray->icon_path, @@ -311,7 +309,13 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) return tray; -error: +icon_dir_error: + SDL_free(tray->icon_dir); + +sdl_dir_error: + SDL_free(sdl_dir); + +tray_error: if (tray) { SDL_free(tray); } @@ -329,8 +333,10 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon) return; } - if (*tray->icon_path) { + if (tray->icon_path) { SDL_RemovePath(tray->icon_path); + SDL_free(tray->icon_path); + tray->icon_path = NULL; } /* AppIndicator caches the icon files; always change filename to avoid caching */ @@ -339,7 +345,8 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon) SDL_SaveBMP(icon, tray->icon_path); app_indicator_set_icon(tray->indicator, tray->icon_path); } else { - *tray->icon_path = '\0'; + SDL_free(tray->icon_path); + tray->icon_path = NULL; app_indicator_set_icon(tray->indicator, NULL); } } @@ -732,12 +739,14 @@ void SDL_DestroyTray(SDL_Tray *tray) DestroySDLMenu(tray->menu); } - if (*tray->icon_path) { + if (tray->icon_path) { SDL_RemovePath(tray->icon_path); + SDL_free(tray->icon_path); } - if (*tray->icon_dir) { + if (tray->icon_dir) { SDL_RemovePath(tray->icon_dir); + SDL_free(tray->icon_dir); } SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); diff --git a/src/tray/windows/SDL_tray.c b/src/tray/windows/SDL_tray.c index a3bd81ff10..15021ac798 100644 --- a/src/tray/windows/SDL_tray.c +++ b/src/tray/windows/SDL_tray.c @@ -216,16 +216,6 @@ void SDL_UpdateTrays(void) { } -bool SDL_IsTraySupported(void) -{ - if (!SDL_IsMainThread()) { - SDL_SetError("This function should be called on the main thread"); - return false; - } - - return true; -} - SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) { if (!SDL_IsMainThread()) { diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 0b8ed8ed5a..1f05ab1c04 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -61,6 +61,7 @@ struct SDL_Window bool fullscreen_exclusive; // The window is currently fullscreen exclusive SDL_DisplayID last_fullscreen_exclusive_display; // The last fullscreen_exclusive display SDL_DisplayID last_displayID; + SDL_DisplayID pending_displayID; /* Stored position and size for the window in the non-fullscreen state, * including when the window is maximized or tiled. diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 1d31cf9bb9..0c2e2f1ebb 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -183,6 +183,7 @@ static VideoBootStrap *bootstrap[] = { #if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA) // Support for macOS fullscreen spaces, etc. extern bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window); +extern bool Cocoa_IsWindowInFullscreenSpaceTransition(SDL_Window *window); extern bool Cocoa_SetWindowFullscreenSpace(SDL_Window *window, bool state, bool blocking); extern bool Cocoa_IsShowingModalDialog(SDL_Window *window); #endif @@ -1174,7 +1175,7 @@ float SDL_GetDisplayContentScale(SDL_DisplayID displayID) void SDL_SetWindowHDRProperties(SDL_Window *window, const SDL_HDROutputProperties *HDR, bool send_event) { - if (window->HDR.HDR_headroom != HDR->HDR_headroom || window->HDR.SDR_white_level != window->HDR.SDR_white_level) { + if (window->HDR.HDR_headroom != HDR->HDR_headroom || window->HDR.SDR_white_level != HDR->SDR_white_level) { SDL_PropertiesID window_props = SDL_GetWindowProperties(window); SDL_SetFloatProperty(window_props, SDL_PROP_WINDOW_HDR_HEADROOM_FLOAT, SDL_max(HDR->HDR_headroom, 1.0f)); @@ -1676,6 +1677,21 @@ SDL_DisplayID SDL_GetDisplayForRect(const SDL_Rect *rect) return GetDisplayForRect(rect->x, rect->y, rect->w, rect->h); } +static SDL_DisplayID GetDisplayAtOrigin(int x, int y) +{ + for (int i = 0; i < _this->num_displays; ++i) { + SDL_Rect rect; + const SDL_DisplayID cur_id = _this->displays[i]->id; + if (SDL_GetDisplayBounds(cur_id, &rect)) { + if (x == rect.x && y == rect.y) { + return cur_id; + } + } + } + + return 0; +} + SDL_DisplayID SDL_GetDisplayForWindowPosition(SDL_Window *window) { int x, y; @@ -1728,6 +1744,9 @@ SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(SDL_Window *window) * window position, or an async window manager hasn't yet actually moved the window, * the current position won't be updated at the time of the fullscreen call. */ + if (!displayID) { + displayID = window->pending_displayID; + } if (!displayID) { // Use the pending position and dimensions, if available, otherwise, use the current. const int x = window->last_position_pending ? window->pending.x : window->x; @@ -1735,7 +1754,11 @@ SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(SDL_Window *window) const int w = window->last_size_pending ? window->pending.w : window->w; const int h = window->last_size_pending ? window->pending.h : window->h; - displayID = GetDisplayForRect(x, y, w, h); + // Check if the window is exactly at the origin of a display. Otherwise, fall back to the generic check. + displayID = GetDisplayAtOrigin(x, y); + if (!displayID) { + displayID = GetDisplayForRect(x, y, w, h); + } } if (!displayID) { // Use the primary display for a window if we can't find it anywhere else @@ -2124,6 +2147,16 @@ bool SDL_SetWindowFullscreenMode(SDL_Window *window, const SDL_DisplayMode *mode * is in progress. It will be overwritten if a new request is made. */ SDL_copyp(&window->current_fullscreen_mode, &window->requested_fullscreen_mode); + +#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA) + /* If this is called while in the middle of a Cocoa fullscreen spaces transition, + * wait until the transition has completed, or the window can wind up in a weird, + * broken state if a mode switch occurs while in a fullscreen space. + */ + if (SDL_strcmp(_this->name, "cocoa") == 0 && Cocoa_IsWindowInFullscreenSpaceTransition(window)) { + SDL_SyncWindow(window); + } +#endif if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) { SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_UPDATE, true); SDL_SyncIfRequired(window); @@ -2356,6 +2389,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props) SDL_Window *parent = (SDL_Window *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, NULL); SDL_WindowFlags flags = SDL_GetWindowFlagProperties(props); SDL_WindowFlags type_flags, graphics_flags; + SDL_DisplayID displayID = 0; bool undefined_x = false; bool undefined_y = false; bool external_graphics_context = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN, false); @@ -2415,7 +2449,6 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props) if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_DisplayID displayID = 0; SDL_Rect bounds; if ((SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) && (x & 0xFFFF)) { @@ -2498,6 +2531,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props) window->floating.h = window->windowed.h = window->h = h; window->undefined_x = undefined_x; window->undefined_y = undefined_y; + window->pending_displayID = displayID; SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); if (display) { @@ -2877,6 +2911,7 @@ bool SDL_SetWindowPosition(SDL_Window *window, int x, int y) const int h = window->last_size_pending ? window->pending.h : window->windowed.h; original_displayID = SDL_GetDisplayForWindow(window); + window->pending_displayID = 0; if (SDL_WINDOWPOS_ISUNDEFINED(x)) { x = window->windowed.x; @@ -2897,6 +2932,8 @@ bool SDL_SetWindowPosition(SDL_Window *window, int x, int y) displayID = SDL_GetPrimaryDisplay(); } + window->pending_displayID = displayID; + SDL_zero(bounds); if (!SDL_GetDisplayUsableBounds(displayID, &bounds) || w > bounds.w || h > bounds.h) { if (!SDL_GetDisplayBounds(displayID, &bounds)) { @@ -2909,6 +2946,12 @@ bool SDL_SetWindowPosition(SDL_Window *window, int x, int y) if (SDL_WINDOWPOS_ISCENTERED(y)) { y = bounds.y + (bounds.h - h) / 2; } + } else { + /* See if the requested window position matches the origin of any displays and set + * the pending fullscreen display ID if it does. This needs to be set early in case + * the window is prevented from moving to the exact origin due to struts. + */ + window->pending_displayID = GetDisplayAtOrigin(x, y); } window->pending.x = x; diff --git a/src/video/android/SDL_androidtouch.c b/src/video/android/SDL_androidtouch.c index 661c9a1674..2e1b6026b1 100644 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -47,6 +47,25 @@ void Android_QuitTouch(void) { } + +SDL_TouchID Android_ConvertJavaTouchID(int touchID) +{ + SDL_TouchID retval = touchID; + + if (touchID < 0) { + // Touch ID -1 appears when using Android emulator, eg: + // adb shell input mouse tap 100 100 + // adb shell input touchscreen tap 100 100 + // + // Prevent to be -1, since it's used in SDL internal for synthetic events: + retval -= 1; + } else { + // Touch ID 0 is invalid + retval += 1; + } + return retval; +} + void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p) { SDL_TouchID touchDeviceId = 0; @@ -56,11 +75,7 @@ void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_fin return; } - /* Touch device -1 appears when using Android emulator, eg: - * adb shell input mouse tap 100 100 - * adb shell input touchscreen tap 100 100 - */ - touchDeviceId = (SDL_TouchID)(touch_device_id_in + 2); + touchDeviceId = Android_ConvertJavaTouchID(touch_device_id_in); // Finger ID should be greater than 0 fingerId = (SDL_FingerID)(pointer_finger_id_in + 1); diff --git a/src/video/android/SDL_androidtouch.h b/src/video/android/SDL_androidtouch.h index 2aef82264d..ae10365e94 100644 --- a/src/video/android/SDL_androidtouch.h +++ b/src/video/android/SDL_androidtouch.h @@ -25,3 +25,4 @@ extern void Android_InitTouch(void); extern void Android_QuitTouch(void); extern void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p); +extern SDL_TouchID Android_ConvertJavaTouchID(int touchID); diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index ecf5980f47..1c790ccb01 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -411,6 +411,19 @@ bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window) } } +bool Cocoa_IsWindowInFullscreenSpaceTransition(SDL_Window *window) +{ + @autoreleasepool { + SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; + + if ([data.listener isInFullscreenSpaceTransition]) { + return true; + } else { + return false; + } + } +} + bool Cocoa_IsWindowZoomed(SDL_Window *window) { SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m index 45f2d64f08..c5b27c0700 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -554,6 +554,14 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char - (void)textFieldTextDidChange:(NSNotification *)notification { + // When opening a password manager overlay to select a password and have it auto-filled, + // text input becomes stopped as a result of the keyboard being hidden or the text field losing focus. + // As a workaround, ensure text input is activated on any changes to the text field. + bool startTextInputMomentarily = !SDL_TextInputActive(window); + + if (startTextInputMomentarily) + SDL_StartTextInput(window); + if (textField.markedTextRange == nil) { NSUInteger compareLength = SDL_min(textField.text.length, committedText.length); NSUInteger matchLength; @@ -588,6 +596,9 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char } committedText = textField.text; } + + if (startTextInputMomentarily) + SDL_StopTextInput(window); } - (void)updateKeyboard @@ -633,7 +644,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char - (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { if (textField.markedTextRange == nil) { - if (textField.text.length < 16) { + if ([string length] == 0 && textField.text.length < 16) { [self resetTextState]; } } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 227246cc92..43f31552cd 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1591,9 +1591,18 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, seat->keyboard.xkb.num_layouts = WAYLAND_xkb_keymap_num_layouts(seat->keyboard.xkb.keymap); if (seat->keyboard.xkb.num_layouts) { seat->keyboard.sdl_keymap = SDL_calloc(seat->keyboard.xkb.num_layouts, sizeof(SDL_Keymap *)); + if (!seat->keyboard.sdl_keymap) { + return; + } + for (xkb_layout_index_t i = 0; i < seat->keyboard.xkb.num_layouts; ++i) { seat->keyboard.sdl_keymap[i] = SDL_CreateKeymap(false); - if (!seat->keyboard.sdl_keymap) { + if (!seat->keyboard.sdl_keymap[i]) { + for (xkb_layout_index_t j = 0; j < i; ++j) { + SDL_DestroyKeymap(seat->keyboard.sdl_keymap[j]); + } + SDL_free(seat->keyboard.sdl_keymap); + seat->keyboard.sdl_keymap = NULL; return; } } @@ -2095,7 +2104,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, Wayland_HandleModifierKeys(seat, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED); // If we have a key with unknown scancode, check if the keysym corresponds to a valid Unicode value, and assign it a reserved scancode. - if (scancode == SDL_SCANCODE_UNKNOWN && syms) { + if (scancode == SDL_SCANCODE_UNKNOWN && syms && seat->keyboard.sdl_keymap) { const SDL_Keycode keycode = (SDL_Keycode)SDL_KeySymToUcs4(syms[0]); if (keycode != SDLK_UNKNOWN) { SDL_Keymod modstate = SDL_KMOD_NONE; diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index e9a97a98f1..68fb9961c8 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -1374,7 +1374,7 @@ static void display_remove_global(void *data, struct wl_registry *registry, uint if (seat->keyboard.wl_keyboard) { SDL_RemoveKeyboard(seat->keyboard.sdl_id, true); } - if (seat->keyboard.wl_keyboard) { + if (seat->pointer.wl_pointer) { SDL_RemoveMouse(seat->pointer.sdl_id, true); } Wayland_SeatDestroy(seat, true); diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 030ce75a0c..bac6179c69 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -2175,7 +2175,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara case WM_NCCALCSIZE: { - SDL_WindowFlags window_flags = SDL_GetWindowFlags(data->window); + SDL_WindowFlags window_flags = data->window->flags; if (wParam == TRUE && (window_flags & SDL_WINDOW_BORDERLESS) && !(window_flags & SDL_WINDOW_FULLSCREEN)) { // When borderless, need to tell windows that the size of the non-client area is 0 NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam; diff --git a/src/video/x11/SDL_x11dyn.h b/src/video/x11/SDL_x11dyn.h index b5bfbf5a09..23b829c2a9 100644 --- a/src/video/x11/SDL_x11dyn.h +++ b/src/video/x11/SDL_x11dyn.h @@ -28,7 +28,7 @@ #include #include -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB #include #endif diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 4d585d3388..67128c85b5 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -248,94 +248,202 @@ static void X11_HandleGenericEvent(SDL_VideoDevice *_this, XEvent *xev) static void X11_UpdateSystemKeyModifiers(SDL_VideoData *viddata) { - Window junk_window; - int x, y; +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + if (viddata->keyboard.xkb_enabled) { + XkbStateRec xkb_state; + if (X11_XkbGetState(viddata->display, XkbUseCoreKbd, &xkb_state) == Success) { + viddata->keyboard.pressed_modifiers = xkb_state.base_mods; + viddata->keyboard.locked_modifiers = xkb_state.latched_mods | xkb_state.locked_mods; + } + } else +#endif + { + Window junk_window; + int x, y; + unsigned int mod_mask; - X11_XQueryPointer(viddata->display, DefaultRootWindow(viddata->display), &junk_window, &junk_window, &x, &y, &x, &y, &viddata->xkb.xkb_modifiers); + X11_XQueryPointer(viddata->display, DefaultRootWindow(viddata->display), &junk_window, &junk_window, &x, &y, &x, &y, &mod_mask); + viddata->keyboard.pressed_modifiers = mod_mask & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask); + viddata->keyboard.locked_modifiers = mod_mask & (LockMask | viddata->keyboard.numlock_mask | viddata->keyboard.scrolllock_mask); + } } -static void X11_ReconcileModifiers(SDL_VideoData *viddata) +static void X11_ReconcileModifiers(SDL_VideoData *viddata, bool key_pressed) { - const Uint32 xk_modifiers = viddata->xkb.xkb_modifiers; - - /* If a modifier was activated by a keypress, it will be tied to the - * specific left/right key that initiated it. Otherwise, the ambiguous - * left/right combo is used. + /* Handle explicit pressed modifier state. This will correct the modifier state + * if common modifier keys were remapped and the modifiers presumed to be set + * during a key press event were incorrect, if the modifier was set to the + * pressed state via means other than pressing the physical key, or if the + * modifier state was set by a keypress before the corresponding key event + * was received. */ - if (xk_modifiers & ShiftMask) { - if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_SHIFT)) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_SHIFT; + if (key_pressed) { + if (viddata->keyboard.pressed_modifiers & ShiftMask) { + if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_SHIFT) { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_SHIFT; + viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_SHIFT); + } + } + + if (viddata->keyboard.pressed_modifiers & ControlMask) { + if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_CTRL) { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_CTRL; + viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_CTRL); + } + } + + if (viddata->keyboard.pressed_modifiers & viddata->keyboard.alt_mask) { + if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_ALT) { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_ALT; + viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_ALT); + } + } + + if (viddata->keyboard.pressed_modifiers & viddata->keyboard.gui_mask) { + if (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_GUI) { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_GUI; + viddata->keyboard.sdl_pressed_modifiers |= (viddata->keyboard.sdl_physically_pressed_modifiers & SDL_KMOD_GUI); + } } } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_SHIFT; + if (viddata->keyboard.pressed_modifiers & ShiftMask) { + if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_SHIFT)) { + viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_SHIFT; + } + } else { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_SHIFT; + } + + if (viddata->keyboard.pressed_modifiers & ControlMask) { + if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_CTRL)) { + viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_CTRL; + } + } else { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_CTRL; + } + + if (viddata->keyboard.pressed_modifiers & viddata->keyboard.alt_mask) { + if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_ALT)) { + viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_ALT; + } + } else { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_ALT; + } + + if (viddata->keyboard.pressed_modifiers & viddata->keyboard.gui_mask) { + if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_GUI)) { + viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_GUI; + } + } else { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_GUI; + } + + if (viddata->keyboard.pressed_modifiers & viddata->keyboard.level3_mask) { + if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_MODE)) { + viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_MODE; + } + } else { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_MODE; + } + + if (viddata->keyboard.pressed_modifiers & viddata->keyboard.level5_mask) { + if (!(viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_LEVEL5)) { + viddata->keyboard.sdl_pressed_modifiers |= SDL_KMOD_LEVEL5; + } + } else { + viddata->keyboard.sdl_pressed_modifiers &= ~SDL_KMOD_LEVEL5; + } } - if (xk_modifiers & ControlMask) { - if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_CTRL)) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_CTRL; + /* If a latch or lock was activated by a keypress, the latch/lock will + * be tied to the specific left/right key that initiated it. Otherwise, + * the ambiguous left/right combo is used. + * + * The modifier will remain active until the latch/lock is released by + * the system. + */ + if (viddata->keyboard.locked_modifiers & ShiftMask) { + if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_SHIFT) { + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_SHIFT; + viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_SHIFT); + } else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_SHIFT)) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_SHIFT; } } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_CTRL; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_SHIFT; } - // Mod1 is used for the Alt keys - if (xk_modifiers & Mod1Mask) { - if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_ALT)) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_ALT; + if (viddata->keyboard.locked_modifiers & ControlMask) { + if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_CTRL) { + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_CTRL; + viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_CTRL); + } else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_CTRL)) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_CTRL; } } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_ALT; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_CTRL; } - // Mod4 is used for the Super (aka GUI/Logo) keys. - if (xk_modifiers & Mod4Mask) { - if (!(viddata->xkb.sdl_modifiers & SDL_KMOD_GUI)) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_GUI; + if (viddata->keyboard.locked_modifiers & viddata->keyboard.alt_mask) { + if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_ALT) { + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_ALT; + viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_ALT); + } else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_ALT)) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_ALT; } } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_GUI; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_ALT; } - // Mod3 is typically Level 5 shift. - if (xk_modifiers & Mod3Mask) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_LEVEL5; + if (viddata->keyboard.locked_modifiers & viddata->keyboard.gui_mask) { + if (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_GUI) { + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_GUI; + viddata->keyboard.sdl_locked_modifiers |= (viddata->keyboard.sdl_pressed_modifiers & SDL_KMOD_GUI); + } else if (!(viddata->keyboard.sdl_locked_modifiers & SDL_KMOD_GUI)) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_GUI; + } } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_LEVEL5; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_GUI; } - // Mod5 is typically Level 3 shift (aka AltGr). - if (xk_modifiers & Mod5Mask) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_MODE; + if (viddata->keyboard.locked_modifiers & viddata->keyboard.level3_mask) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_MODE; } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_MODE; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_MODE; } - if (xk_modifiers & LockMask) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_CAPS; + if (viddata->keyboard.locked_modifiers & viddata->keyboard.level5_mask) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_LEVEL5; } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_CAPS; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_LEVEL5; } - if (xk_modifiers & viddata->xkb.numlock_mask) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_NUM; + // Capslock, Numlock, and Scrolllock can only be locked, not pressed. + if (viddata->keyboard.locked_modifiers & LockMask) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_CAPS; } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_NUM; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_CAPS; } - if (xk_modifiers & viddata->xkb.scrolllock_mask) { - viddata->xkb.sdl_modifiers |= SDL_KMOD_SCROLL; + if (viddata->keyboard.locked_modifiers & viddata->keyboard.numlock_mask) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_NUM; } else { - viddata->xkb.sdl_modifiers &= ~SDL_KMOD_SCROLL; + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_NUM; } - SDL_SetModState(viddata->xkb.sdl_modifiers); + if (viddata->keyboard.locked_modifiers & viddata->keyboard.scrolllock_mask) { + viddata->keyboard.sdl_locked_modifiers |= SDL_KMOD_SCROLL; + } else { + viddata->keyboard.sdl_locked_modifiers &= ~SDL_KMOD_SCROLL; + } + + SDL_SetModState(viddata->keyboard.sdl_pressed_modifiers | viddata->keyboard.sdl_locked_modifiers); } -static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode, bool pressed, bool allow_reconciliation) +static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode, bool pressed) { const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false); SDL_Keymod mod = SDL_KMOD_NONE; - bool reconcile = false; /* SDL clients expect modifier state to be activated at the same time as the * source keypress, so we set pressed modifier state with the usual modifier @@ -378,48 +486,46 @@ static void X11_HandleModifierKeys(SDL_VideoData *viddata, SDL_Scancode scancode case SDLK_NUMLOCKCLEAR: case SDLK_SCROLLLOCK: { - /* For locking modifier keys, query the lock state directly, or we may have to wait until the next - * key press event to know if a lock was actually activated from the key event. - */ - unsigned int cur_mask = viddata->xkb.xkb_modifiers; - X11_UpdateSystemKeyModifiers(viddata); + // XKB provides the latched/locked state explicitly. + if (viddata->keyboard.xkb_enabled) { + /* For locking modifier keys, query the lock state directly, or we may have to wait until the next + * key press event to know if a lock was actually activated from the key event. + */ + unsigned int cur_mask = viddata->keyboard.locked_modifiers; + X11_UpdateSystemKeyModifiers(viddata); - if (viddata->xkb.xkb_modifiers & LockMask) { - cur_mask |= LockMask; - } else { - cur_mask &= ~LockMask; - } - if (viddata->xkb.xkb_modifiers & viddata->xkb.numlock_mask) { - cur_mask |= viddata->xkb.numlock_mask; - } else { - cur_mask &= ~viddata->xkb.numlock_mask; - } - if (viddata->xkb.xkb_modifiers & viddata->xkb.scrolllock_mask) { - cur_mask |= viddata->xkb.scrolllock_mask; - } else { - cur_mask &= ~viddata->xkb.scrolllock_mask; - } + if (viddata->keyboard.locked_modifiers & LockMask) { + cur_mask |= LockMask; + } else { + cur_mask &= ~LockMask; + } + if (viddata->keyboard.locked_modifiers & viddata->keyboard.numlock_mask) { + cur_mask |= viddata->keyboard.numlock_mask; + } else { + cur_mask &= ~viddata->keyboard.numlock_mask; + } + if (viddata->keyboard.locked_modifiers & viddata->keyboard.scrolllock_mask) { + cur_mask |= viddata->keyboard.scrolllock_mask; + } else { + cur_mask &= ~viddata->keyboard.scrolllock_mask; + } - viddata->xkb.xkb_modifiers = cur_mask; - } SDL_FALLTHROUGH; + viddata->keyboard.locked_modifiers = cur_mask; + } + } break; default: - reconcile = true; - break; + return; } if (pressed) { - viddata->xkb.sdl_modifiers |= mod; + viddata->keyboard.sdl_pressed_modifiers |= mod; + viddata->keyboard.sdl_physically_pressed_modifiers |= mod; } else { - viddata->xkb.sdl_modifiers &= ~mod; + viddata->keyboard.sdl_pressed_modifiers &= ~mod; + viddata->keyboard.sdl_physically_pressed_modifiers &= ~mod; } - if (allow_reconciliation) { - if (reconcile) { - X11_ReconcileModifiers(viddata); - } else { - SDL_SetModState(viddata->xkb.sdl_modifiers); - } - } + X11_ReconcileModifiers(viddata, true); } void X11_ReconcileKeyboardState(SDL_VideoDevice *_this) @@ -427,18 +533,25 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this) SDL_VideoData *videodata = _this->internal; Display *display = videodata->display; char keys[32]; - int keycode; - const bool *keyboardState; + + // Rebuild the modifier state in case it changed while focus was lost. + X11_UpdateSystemKeyModifiers(videodata); + X11_ReconcileModifiers(videodata, false); + + // Keep caps, num, and scroll, but clear the others until we have updated key state. + videodata->keyboard.sdl_pressed_modifiers = 0; + videodata->keyboard.sdl_physically_pressed_modifiers = 0; + videodata->keyboard.sdl_locked_modifiers &= SDL_KMOD_CAPS | SDL_KMOD_NUM | SDL_KMOD_SCROLL; + videodata->keyboard.pressed_modifiers = 0; + videodata->keyboard.locked_modifiers &= LockMask | videodata->keyboard.numlock_mask| videodata->keyboard.scrolllock_mask; X11_XQueryKeymap(display, keys); - keyboardState = SDL_GetKeyboardState(0); - for (keycode = 0; keycode < SDL_arraysize(videodata->key_layout); ++keycode) { - SDL_Scancode scancode = videodata->key_layout[keycode]; - bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0; - bool sdlKeyPressed = keyboardState[scancode]; + for (Uint32 keycode = 0; keycode < SDL_arraysize(videodata->keyboard.key_layout); ++keycode) { + const SDL_Scancode scancode = videodata->keyboard.key_layout[keycode]; + const bool x11KeyPressed = (keys[keycode / 8] & (1 << (keycode % 8))) != 0; - if (x11KeyPressed && !sdlKeyPressed) { + if (x11KeyPressed) { // Only update modifier state for keys that are pressed in another application switch (SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false)) { case SDLK_LCTRL: @@ -451,20 +564,18 @@ void X11_ReconcileKeyboardState(SDL_VideoDevice *_this) case SDLK_RGUI: case SDLK_MODE: case SDLK_LEVEL5_SHIFT: - X11_HandleModifierKeys(videodata, scancode, true, false); + X11_HandleModifierKeys(videodata, scancode, true); SDL_SendKeyboardKeyIgnoreModifiers(0, SDL_GLOBAL_KEYBOARD_ID, keycode, scancode, true); break; default: break; } - } else if (!x11KeyPressed && sdlKeyPressed) { - X11_HandleModifierKeys(videodata, scancode, false, false); - SDL_SendKeyboardKeyIgnoreModifiers(0, SDL_GLOBAL_KEYBOARD_ID, keycode, scancode, false); } } + // Update the latched/locked state for modifiers other than Caps, Num, and Scroll lock. X11_UpdateSystemKeyModifiers(videodata); - X11_ReconcileModifiers(videodata); + X11_ReconcileModifiers(videodata, false); } static void X11_DispatchFocusIn(SDL_VideoDevice *_this, SDL_WindowData *data) @@ -850,16 +961,6 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven } } -static void X11_HandleSettingsEvent(SDL_VideoDevice *_this, const XEvent *xevent) -{ - SDL_VideoData *videodata = _this->internal; - - SDL_assert(videodata->xsettings_window != None); - SDL_assert(xevent->xany.window == videodata->xsettings_window); - - X11_HandleXsettings(_this, xevent); -} - static Bool isMapNotify(Display *display, XEvent *ev, XPointer arg) { XUnmapEvent *unmap; @@ -943,7 +1044,7 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_ Status status = 0; bool handled_by_ime = false; bool pressed = (xevent->type == KeyPress); - SDL_Scancode scancode = videodata->key_layout[keycode]; + SDL_Scancode scancode = videodata->keyboard.key_layout[keycode]; Uint64 timestamp = X11_GetEventTimestamp(xevent->xkey.time); #ifdef DEBUG_XEVENTS @@ -961,7 +1062,12 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_ #endif // DEBUG SCANCODES text[0] = '\0'; - videodata->xkb.xkb_modifiers = xevent->xkey.state; + + // XKB updates the modifiers explicitly via a state event. + if (!videodata->keyboard.xkb_enabled) { + videodata->keyboard.pressed_modifiers = xevent->xkey.state & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask); + videodata->keyboard.locked_modifiers = xevent->xkey.state & (LockMask | videodata->keyboard.numlock_mask | videodata->keyboard.scrolllock_mask); + } if (SDL_TextInputActive(windowdata->window)) { // filter events catches XIM events and sends them to the correct handler @@ -989,7 +1095,7 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_ if (!handled_by_ime) { if (pressed) { - X11_HandleModifierKeys(videodata, scancode, true, true); + X11_HandleModifierKeys(videodata, scancode, true); SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, true); if (*text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) { @@ -1003,7 +1109,7 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_ return; } - X11_HandleModifierKeys(videodata, scancode, false, true); + X11_HandleModifierKeys(videodata, scancode, false); SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, false); } } @@ -1228,47 +1334,85 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) return; } - if ((videodata->xsettings_window != None) && - (videodata->xsettings_window == xevent->xany.window)) { - X11_HandleSettingsEvent(_this, xevent); - return; - } + // xsettings internally filters events for the windows it watches + X11_HandleXsettingsEvent(_this, xevent); data = X11_FindWindow(_this, xevent->xany.window); if (!data) { // The window for KeymapNotify, etc events is 0 +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + if (videodata->keyboard.xkb_enabled && xevent->type == videodata->keyboard.xkb.event) { + XkbEvent *xkbevent = (XkbEvent *)xevent; + switch (xkbevent->any.xkb_type) { + case XkbStateNotify: + { +#ifdef DEBUG_XEVENTS + SDL_Log("window 0x%lx: XkbStateNotify!", xevent->xany.window); +#endif + if ((xkbevent->state.changed & XkbGroupStateMask) && xkbevent->state.group != videodata->keyboard.xkb.current_group) { + videodata->keyboard.xkb.current_group = xkbevent->state.group; + SDL_SetKeymap(videodata->keyboard.xkb.keymaps[videodata->keyboard.xkb.current_group], true); + } + + if (xkbevent->state.changed & XkbModifierStateMask) { + videodata->keyboard.pressed_modifiers = xkbevent->state.base_mods; + videodata->keyboard.locked_modifiers = xkbevent->state.latched_mods | xkbevent->state.locked_mods; + X11_ReconcileModifiers(videodata, false); + } + } break; + + case XkbMapNotify: +#ifdef DEBUG_XEVENTS + SDL_Log("window 0x%lx: XkbMapNotify!", xevent->xany.window); + SDL_FALLTHROUGH; +#endif + case XkbNewKeyboardNotify: + { +#ifdef DEBUG_XEVENTS + if (xkbevent->any.xkb_type == XkbNewKeyboardNotify) { + SDL_Log("window 0x%lx: XkbNewKeyboardNotify!", xevent->xany.window); + } +#endif + X11_XkbRefreshKeyboardMapping(&xkbevent->map); + + // Don't redundantly rebuild the keymap if this is a duplicate event. + if (xkbevent->any.serial != videodata->keyboard.xkb.last_map_serial) { + videodata->keyboard.xkb.last_map_serial = xkbevent->any.serial; + X11_UpdateKeymap(_this, true); + } + } break; + + default: + break; + } + } else +#endif if (xevent->type == KeymapNotify) { #ifdef DEBUG_XEVENTS SDL_Log("window 0x%lx: KeymapNotify!", xevent->xany.window); #endif - if (SDL_GetKeyboardFocus() != NULL) { -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM - if (videodata->xkb.desc_ptr) { - XkbStateRec state; - if (X11_XkbGetState(videodata->display, XkbUseCoreKbd, &state) == Success) { - if (state.group != videodata->xkb.current_group) { - // Only rebuild the keymap if the layout has changed. - videodata->xkb.current_group = state.group; - X11_UpdateKeymap(_this, true); - } - } + if (!videodata->keyboard.xkb_enabled) { + if (SDL_GetKeyboardFocus() != NULL) { + X11_UpdateKeymap(_this, true); } -#endif - X11_ReconcileKeyboardState(_this); } + + X11_ReconcileKeyboardState(_this); } else if (xevent->type == MappingNotify) { - // Has the keyboard layout changed? - const int request = xevent->xmapping.request; + if (!videodata->keyboard.xkb_enabled) { + // Has the keyboard layout changed? + const int request = xevent->xmapping.request; #ifdef DEBUG_XEVENTS - SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window); + SDL_Log("window 0x%lx: MappingNotify!", xevent->xany.window); #endif - if ((request == MappingKeyboard) || (request == MappingModifier)) { - X11_XRefreshKeyboardMapping(&xevent->xmapping); - } + if ((request == MappingKeyboard) || (request == MappingModifier)) { + X11_XRefreshKeyboardMapping(&xevent->xmapping); + } - X11_UpdateKeymap(_this, true); + X11_UpdateKeymap(_this, true); + } } else if (xevent->type == PropertyNotify && videodata && videodata->windowlist) { char *name_of_atom = X11_XGetAtomName(display, xevent->xproperty.atom); diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index 8406f48671..d26087a12f 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/src/video/x11/SDL_x11keyboard.c @@ -28,7 +28,10 @@ #include "../../events/SDL_scancode_tables_c.h" #include + +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB #include +#endif #include "../../events/imKStoUCS.h" #include "../../events/SDL_keysym_to_scancode_c.h" @@ -70,6 +73,28 @@ static bool X11_ScancodeIsRemappable(SDL_Scancode scancode) } } +static KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned int group, unsigned int level) +{ + SDL_VideoData *data = _this->internal; + KeySym keysym; + +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + if (data->keyboard.xkb_enabled) { + keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, level); + } else +#endif + { + // TODO: Handle groups on the legacy path. + if (keycode >= data->keyboard.core.min_keycode && keycode <= data->keyboard.core.max_keycode) { + keysym = data->keyboard.core.keysym_map[(keycode - data->keyboard.core.min_keycode) * data->keyboard.core.keysyms_per_key]; + } else { + keysym = NoSymbol; + } + } + + return keysym; +} + // This function only correctly maps letters and numbers for keyboards in US QWERTY layout static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode keycode) { @@ -82,48 +107,6 @@ static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode key return SDL_GetScancodeFromKeySym(keysym, keycode); } -KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group, unsigned int mod_mask) -{ - SDL_VideoData *data = _this->internal; - KeySym keysym; - unsigned int mods_ret[16]; - - SDL_zero(mods_ret); - -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM - if (data->xkb.desc_ptr) { - int num_groups = XkbKeyNumGroups(data->xkb.desc_ptr, keycode); - unsigned char info = XkbKeyGroupInfo(data->xkb.desc_ptr, keycode); - - if (num_groups && group >= num_groups) { - - int action = XkbOutOfRangeGroupAction(info); - - if (action == XkbRedirectIntoRange) { - group = XkbOutOfRangeGroupNumber(info); - if (group >= num_groups) { - group = 0; - } - } else if (action == XkbClampIntoRange) { - group = num_groups - 1; - } else { - group %= num_groups; - } - } - - if (X11_XkbLookupKeySym(data->display, keycode, XkbBuildCoreState(mod_mask, group), mods_ret, &keysym) == NoSymbol) { - keysym = NoSymbol; - } - } else -#endif - { - // TODO: Handle groups and modifiers on the legacy path. - keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); - } - - return keysym; -} - bool X11_InitKeyboard(SDL_VideoDevice *_this) { SDL_VideoData *data = _this->internal; @@ -146,21 +129,33 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) int best_distance; int best_index; int distance; - Bool xkb_repeat = 0; -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM - { - int xkb_major = XkbMajorVersion; - int xkb_minor = XkbMinorVersion; +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + int xkb_major = XkbMajorVersion; + int xkb_minor = XkbMinorVersion; - if (X11_XkbQueryExtension(data->display, NULL, &data->xkb.event, NULL, &xkb_major, &xkb_minor)) { - data->xkb.desc_ptr = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd); - } + if (X11_XkbQueryExtension(data->display, NULL, &data->keyboard.xkb.event, NULL, &xkb_major, &xkb_minor)) { + Bool xkb_repeat = 0; + data->keyboard.xkb_enabled = true; + data->keyboard.xkb.desc_ptr = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd); - // This will remove KeyRelease events for held keys + // This will remove KeyRelease events for held keys. X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat); - } + + // Enable the key mapping and state events. + X11_XkbSelectEvents(data->display, XkbUseCoreKbd, + XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask, + XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask); + X11_XkbSelectEventDetails(data->display, XkbUseCoreKbd, XkbStateNotify, XkbGroupStateMask | XkbModifierStateMask, XkbGroupStateMask | XkbModifierStateMask); + } else #endif + { + // If XKB isn't available, initialize the legacy path. + X11_XDisplayKeycodes(data->display, &data->keyboard.core.min_keycode, &data->keyboard.core.max_keycode); + data->keyboard.core.keysym_map = X11_XGetKeyboardMapping(data->display, data->keyboard.core.min_keycode, + data->keyboard.core.max_keycode - data->keyboard.core.min_keycode, + &data->keyboard.core.keysyms_per_key); + } // Open a connection to the X input manager #ifdef X_HAVE_UTF8_STRING @@ -242,10 +237,10 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d", best_index, min_keycode, max_keycode, table_size); #endif // This should never happen, but just in case... - if (table_size > (SDL_arraysize(data->key_layout) - min_keycode)) { - table_size = (SDL_arraysize(data->key_layout) - min_keycode); + if (table_size > (SDL_arraysize(data->keyboard.key_layout) - min_keycode)) { + table_size = (SDL_arraysize(data->keyboard.key_layout) - min_keycode); } - SDL_memcpy(&data->key_layout[min_keycode], table, sizeof(SDL_Scancode) * table_size); + SDL_memcpy(&data->keyboard.key_layout[min_keycode], table, sizeof(SDL_Scancode) * table_size); /* Scancodes represent physical locations on the keyboard, unaffected by keyboard mapping. However, there are a number of extended scancodes that have no standard location, so use @@ -261,7 +256,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) (unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym)); } #endif - if (scancode == data->key_layout[i]) { + if (scancode == data->keyboard.key_layout[i]) { continue; } if ((SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & (SDLK_SCANCODE_MASK | SDLK_EXTENDED_MASK)) && X11_ScancodeIsRemappable(scancode)) { @@ -269,7 +264,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) #ifdef DEBUG_KEYBOARD SDL_Log("Changing scancode, was %d (%s), now %d (%s)", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode)); #endif - data->key_layout[i] = scancode; + data->keyboard.key_layout[i] = scancode; } } } else { @@ -293,7 +288,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) SDL_Log("scancode = %d (%s)", scancode, SDL_GetScancodeName(scancode)); } #endif - data->key_layout[i] = scancode; + data->keyboard.key_layout[i] = scancode; } } @@ -306,149 +301,236 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) return true; } -static unsigned X11_GetNumLockModifierMask(SDL_VideoDevice *_this) +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB +static unsigned int X11_GetXkbVirtualModifierMask(SDL_VideoDevice *_this, const char *vmod_name) +{ + SDL_VideoData *videodata = _this->internal; + unsigned int mod_mask = 0; + + if (videodata->keyboard.xkb_enabled) { + Atom vmod = X11_XInternAtom(videodata->display, vmod_name, True); + if (vmod != None) { + for (int i = 0; i < XkbNumVirtualMods; ++i) { + if (vmod == videodata->keyboard.xkb.desc_ptr->names->vmods[i]) { + mod_mask = videodata->keyboard.xkb.desc_ptr->server->vmods[i]; + break; + } + } + } + } + + return mod_mask; +} +#endif + +static unsigned X11_GetXModifierMask(SDL_VideoDevice *_this, SDL_Scancode scancode) { SDL_VideoData *videodata = _this->internal; Display *display = videodata->display; - unsigned num_mask = 0; - int i, j; - XModifierKeymap *xmods; - unsigned n; + unsigned int mod_mask = 0; - xmods = X11_XGetModifierMapping(display); - n = xmods->max_keypermod; - for (i = 3; i < 8; i++) { - for (j = 0; j < n; j++) { - KeyCode kc = xmods->modifiermap[i * n + j]; - if (videodata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) { - num_mask = 1 << i; + XModifierKeymap *xmods = X11_XGetModifierMapping(display); + unsigned int n = xmods->max_keypermod; + for (int i = 3; i < 8; i++) { + for (int j = 0; j < n; j++) { + const KeyCode kc = xmods->modifiermap[i * n + j]; + if (videodata->keyboard.key_layout[kc] == scancode) { + mod_mask = 1 << i; break; } } } X11_XFreeModifiermap(xmods); - return num_mask; + return mod_mask; } -static unsigned X11_GetScrollLockModifierMask(SDL_VideoDevice *_this) +static void X11_AddKeymapEntry(SDL_Keymap *keymap, Uint32 xkeycode, KeySym xkeysym, SDL_Scancode sdl_scancode, SDL_Keymod sdl_mod_mask) { - SDL_VideoData *videodata = _this->internal; - Display *display = videodata->display; - unsigned num_mask = 0; - int i, j; - XModifierKeymap *xmods; - unsigned n; + SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(xkeysym, xkeycode, sdl_mod_mask); - xmods = X11_XGetModifierMapping(display); - n = xmods->max_keypermod; - for (i = 3; i < 8; i++) { - for (j = 0; j < n; j++) { - KeyCode kc = xmods->modifiermap[i * n + j]; - if (videodata->key_layout[kc] == SDL_SCANCODE_SCROLLLOCK) { - num_mask = 1 << i; - break; - } + if (!keycode) { + switch (sdl_scancode) { + case SDL_SCANCODE_RETURN: + keycode = SDLK_RETURN; + break; + case SDL_SCANCODE_ESCAPE: + keycode = SDLK_ESCAPE; + break; + case SDL_SCANCODE_BACKSPACE: + keycode = SDLK_BACKSPACE; + break; + case SDL_SCANCODE_DELETE: + keycode = SDLK_DELETE; + break; + default: + keycode = SDL_SCANCODE_TO_KEYCODE(sdl_scancode); + break; } } - X11_XFreeModifiermap(xmods); - return num_mask; + SDL_SetKeymapEntry(keymap, sdl_scancode, sdl_mod_mask, keycode); } void X11_UpdateKeymap(SDL_VideoDevice *_this, bool send_event) { - struct Keymod_masks - { - SDL_Keymod sdl_mask; - unsigned int xkb_mask; - } const keymod_masks[] = { - { SDL_KMOD_NONE, 0 }, - { SDL_KMOD_SHIFT, ShiftMask }, - { SDL_KMOD_CAPS, LockMask }, - { SDL_KMOD_SHIFT | SDL_KMOD_CAPS, ShiftMask | LockMask }, - { SDL_KMOD_MODE, Mod5Mask }, - { SDL_KMOD_MODE | SDL_KMOD_SHIFT, Mod5Mask | ShiftMask }, - { SDL_KMOD_MODE | SDL_KMOD_CAPS, Mod5Mask | LockMask }, - { SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod5Mask | ShiftMask | LockMask }, - { SDL_KMOD_LEVEL5, Mod3Mask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT, Mod3Mask | ShiftMask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_CAPS, Mod3Mask | LockMask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod3Mask | ShiftMask | LockMask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE, Mod5Mask | Mod3Mask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT, Mod3Mask | Mod5Mask | ShiftMask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_CAPS, Mod3Mask | Mod5Mask | LockMask }, - { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod3Mask | Mod5Mask | ShiftMask | LockMask } - }; - SDL_VideoData *data = _this->internal; - SDL_Scancode scancode; - SDL_Keymap *keymap = SDL_CreateKeymap(true); -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM - if (data->xkb.desc_ptr) { +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + if (data->keyboard.xkb_enabled) { XkbStateRec state; - X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb.desc_ptr); + + SDL_SetKeymap(NULL, false); + for (unsigned int i = 0; i < XkbNumKbdGroups; ++i) { + SDL_DestroyKeymap(data->keyboard.xkb.keymaps[i]); + data->keyboard.xkb.keymaps[i] = SDL_CreateKeymap(false); + } + + X11_XkbGetNames(data->display, XkbVirtualModNamesMask, data->keyboard.xkb.desc_ptr); + X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask | XkbVirtualModsMask, data->keyboard.xkb.desc_ptr); if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) { - data->xkb.current_group = state.group; + data->keyboard.xkb.current_group = state.group; } - } -#endif - for (int m = 0; m < SDL_arraysize(keymod_masks); ++m) { - for (int i = 0; i < SDL_arraysize(data->key_layout); ++i) { - // Make sure this is a valid scancode - scancode = data->key_layout[i]; + data->keyboard.alt_mask = X11_GetXkbVirtualModifierMask(_this, "Alt"); + if (!data->keyboard.alt_mask) { + data->keyboard.alt_mask = X11_GetXkbVirtualModifierMask(_this, "Meta"); + } + data->keyboard.gui_mask = X11_GetXkbVirtualModifierMask(_this, "Super"); + data->keyboard.level3_mask = X11_GetXkbVirtualModifierMask(_this, "LevelThree"); + data->keyboard.level5_mask = X11_GetXkbVirtualModifierMask(_this, "LevelFive"); + data->keyboard.numlock_mask = X11_GetXkbVirtualModifierMask(_this, "NumLock"); + data->keyboard.scrolllock_mask = X11_GetXkbVirtualModifierMask(_this, "ScrollLock"); + + const Uint32 valid_mod_mask = ShiftMask | LockMask | data->keyboard.alt_mask | data->keyboard.level3_mask | data->keyboard.level5_mask; + + for (Uint32 xkeycode = data->keyboard.xkb.desc_ptr->min_key_code; xkeycode < data->keyboard.xkb.desc_ptr->max_key_code; ++xkeycode) { + const SDL_Scancode scancode = data->keyboard.key_layout[xkeycode]; if (scancode == SDL_SCANCODE_UNKNOWN) { continue; } - const KeySym keysym = X11_KeyCodeToSym(_this, i, data->xkb.current_group, keymod_masks[m].xkb_mask); + for (Uint32 group = 0; group < XkbNumKbdGroups; ++group) { + SDL_Keymap *keymap = data->keyboard.xkb.keymaps[group]; - if (keysym != NoSymbol) { - SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(keysym, i, keymod_masks[m].sdl_mask); + Uint32 effective_group = group; + const unsigned char max_key_group = XkbKeyNumGroups(data->keyboard.xkb.desc_ptr, xkeycode); + const unsigned char key_group_info = XkbKeyGroupInfo(data->keyboard.xkb.desc_ptr, xkeycode); - if (!keycode) { - switch (scancode) { - case SDL_SCANCODE_RETURN: - keycode = SDLK_RETURN; - break; - case SDL_SCANCODE_ESCAPE: - keycode = SDLK_ESCAPE; - break; - case SDL_SCANCODE_BACKSPACE: - keycode = SDLK_BACKSPACE; - break; - case SDL_SCANCODE_DELETE: - keycode = SDLK_DELETE; - break; + if (max_key_group && effective_group >= max_key_group) { + const unsigned char action = XkbOutOfRangeGroupAction(key_group_info); + + switch (action) { default: - keycode = SDL_SCANCODE_TO_KEYCODE(scancode); + effective_group %= max_key_group; + break; + case XkbClampIntoRange: + effective_group = max_key_group - 1; + break; + case XkbRedirectIntoRange: + effective_group = XkbOutOfRangeGroupNumber(key_group_info); + if (effective_group >= max_key_group) { + effective_group = 0; + } break; } } - SDL_SetKeymapEntry(keymap, scancode, keymod_masks[m].sdl_mask, keycode); + XkbKeyTypePtr key_type = XkbKeyKeyType(data->keyboard.xkb.desc_ptr, xkeycode, effective_group); + + for (Uint32 level = 0; level < key_type->num_levels; ++level) { + const KeySym keysym = X11_KeyCodeToSym(_this, xkeycode, effective_group, level); + + if (keysym != NoSymbol) { + bool key_added = false; + + for (int map_idx = 0; map_idx < key_type->map_count; ++map_idx) { + if (key_type->map[map_idx].active && key_type->map[map_idx].level == level) { + const unsigned int xkb_mod_mask = key_type->map[map_idx].mods.mask; + if ((xkb_mod_mask | valid_mod_mask) == valid_mod_mask) { + const SDL_Keymod sdl_mod_mask = (xkb_mod_mask & ShiftMask ? SDL_KMOD_SHIFT : 0) | + (xkb_mod_mask & LockMask ? SDL_KMOD_CAPS : 0) | + (xkb_mod_mask & data->keyboard.alt_mask ? SDL_KMOD_ALT : 0) | + (xkb_mod_mask & data->keyboard.level3_mask ? SDL_KMOD_MODE : 0) | + (xkb_mod_mask & data->keyboard.level5_mask ? SDL_KMOD_LEVEL5 : 0); + + X11_AddKeymapEntry(keymap, xkeycode, keysym, scancode, sdl_mod_mask); + key_added = true; + } + } + } + + // Add the unmodified key for level 0. + if (!level && !key_added) { + X11_AddKeymapEntry(keymap, xkeycode, keysym, scancode, 0); + } + } + } } } - } - data->xkb.numlock_mask = X11_GetNumLockModifierMask(_this); - data->xkb.scrolllock_mask = X11_GetScrollLockModifierMask(_this); - SDL_SetKeymap(keymap, send_event); + SDL_SetKeymap(data->keyboard.xkb.keymaps[data->keyboard.xkb.current_group], send_event); + } else +#endif + { + SDL_Keymap *keymap = SDL_CreateKeymap(true); + + if (send_event) { + if (data->keyboard.core.keysym_map) { + X11_XFree(data->keyboard.core.keysym_map); + } + X11_XDisplayKeycodes(data->display, &data->keyboard.core.min_keycode, &data->keyboard.core.max_keycode); + data->keyboard.core.keysym_map = X11_XGetKeyboardMapping(data->display, data->keyboard.core.min_keycode, + data->keyboard.core.max_keycode - data->keyboard.core.min_keycode, + &data->keyboard.core.keysyms_per_key); + } + + for (Uint32 xkeycode = data->keyboard.core.min_keycode; xkeycode <= data->keyboard.core.max_keycode; ++xkeycode) { + const SDL_Scancode scancode = data->keyboard.key_layout[xkeycode]; + if (scancode == SDL_SCANCODE_UNKNOWN) { + continue; + } + + const KeySym keysym = X11_KeyCodeToSym(_this, xkeycode, 0, 0); + if (keysym != NoSymbol) { + X11_AddKeymapEntry(keymap, xkeycode, keysym, scancode, 0); + } + } + + data->keyboard.alt_mask = Mod1Mask; // Alt or Meta + data->keyboard.gui_mask = Mod4Mask; // Super + data->keyboard.level3_mask = Mod5Mask; // Note: Not a typo, Mod5 = level 3 shift, and Mod3 = level 5 shift. + data->keyboard.level5_mask = Mod3Mask; + data->keyboard.numlock_mask = X11_GetXModifierMask(_this, SDL_SCANCODE_NUMLOCKCLEAR); + data->keyboard.scrolllock_mask = X11_GetXModifierMask(_this, SDL_SCANCODE_SCROLLLOCK); + + SDL_SetKeymap(keymap, send_event); + } } void X11_QuitKeyboard(SDL_VideoDevice *_this) { SDL_VideoData *data = _this->internal; -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM - if (data->xkb.desc_ptr) { - X11_XkbFreeKeyboard(data->xkb.desc_ptr, 0, True); - data->xkb.desc_ptr = NULL; - } +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + if (data->keyboard.xkb_enabled) { + SDL_SetKeymap(NULL, false); + for (int i = 0; i < XkbNumKbdGroups; ++i) { + SDL_DestroyKeymap(data->keyboard.xkb.keymaps[i]); + data->keyboard.xkb.keymaps[i] = NULL; + } + + if (data->keyboard.xkb_enabled) { + X11_XkbFreeKeyboard(data->keyboard.xkb.desc_ptr, 0, True); + data->keyboard.xkb.desc_ptr = NULL; + } + } else #endif + if (data->keyboard.core.keysym_map) { + X11_XFree(data->keyboard.core.keysym_map); + data->keyboard.core.keysym_map = NULL; + } } void X11_ClearComposition(SDL_WindowData *data) diff --git a/src/video/x11/SDL_x11keyboard.h b/src/video/x11/SDL_x11keyboard.h index a6cd2f7e97..bc053f5fbb 100644 --- a/src/video/x11/SDL_x11keyboard.h +++ b/src/video/x11/SDL_x11keyboard.h @@ -35,6 +35,5 @@ extern bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this); extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props); extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window); extern bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window); -extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group, unsigned int mod_mask); #endif // SDL_x11keyboard_h_ diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index 2417d33f17..cab71150c0 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -48,90 +48,95 @@ */ // #define XRANDR_DISABLED_BY_DEFAULT -static float GetGlobalContentScale(SDL_VideoDevice *_this) +float X11_GetGlobalContentScale(SDL_VideoDevice *_this) { - static double scale_factor = 0.0; + double scale_factor = 0.0; - if (scale_factor <= 0.0) { + // First use the forced scaling factor specified by the app/user + const char *hint = SDL_GetHint(SDL_HINT_VIDEO_X11_SCALING_FACTOR); + if (hint && *hint) { + double value = SDL_atof(hint); + if (value >= 1.0f && value <= 10.0f) { + scale_factor = value; + } + } - // First use the forced scaling factor specified by the app/user - const char *hint = SDL_GetHint(SDL_HINT_VIDEO_X11_SCALING_FACTOR); - if (hint && *hint) { - double value = SDL_atof(hint); - if (value >= 1.0f && value <= 10.0f) { - scale_factor = value; - } + // If that failed, try "Xft.dpi" from the XResourcesDatabase... + // We attempt to read this directly to get the live value, XResourceManagerString + // is cached per display connection. + if (scale_factor <= 0.0) + { + SDL_VideoData *data = _this->internal; + Display *display = data->display; + int status, real_format; + Atom real_type; + unsigned long items_read, items_left; + char *resource_manager; + bool owns_resource_manager = false; + + X11_XrmInitialize(); + status = X11_XGetWindowProperty(display, RootWindow(display, DefaultScreen(display)), + data->atoms.RESOURCE_MANAGER, 0L, 8192L, False, XA_STRING, + &real_type, &real_format, &items_read, &items_left, + (unsigned char **)&resource_manager); + + if (status == Success && resource_manager) { + owns_resource_manager = true; + } else { + // Fall back to XResourceManagerString. This will not be updated if the + // dpi value is later changed but should allow getting the initial value. + resource_manager = X11_XResourceManagerString(display); } - // If that failed, try "Xft.dpi" from GTK if available. On XWayland this - // will retrieve the current scale factor which is not updated dynamically - // in the Xrm database. - SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); - if (gtk) { - GtkSettings *gtksettings = gtk->gtk.settings_get_default(); - if (gtksettings) { - int dpi = 0; - gtk->g.object_get(gtksettings, "gtk-xft-dpi", &dpi, NULL); - scale_factor = dpi / 1024.0 / 96.0; - } - SDL_Gtk_ExitContext(gtk); - } - - // If that failed, try "Xft.dpi" from the XResourcesDatabase... - if (scale_factor <= 0.0) - { - SDL_VideoData *data = _this->internal; - Display *display = data->display; - char *resource_manager; + if (resource_manager) { XrmDatabase db; XrmValue value; char *type; - X11_XrmInitialize(); + db = X11_XrmGetStringDatabase(resource_manager); - resource_manager = X11_XResourceManagerString(display); - if (resource_manager) { - db = X11_XrmGetStringDatabase(resource_manager); - - // Get the value of Xft.dpi from the Database - if (X11_XrmGetResource(db, "Xft.dpi", "String", &type, &value)) { - if (value.addr && type && SDL_strcmp(type, "String") == 0) { - int dpi = SDL_atoi(value.addr); - scale_factor = dpi / 96.0; - } - } - X11_XrmDestroyDatabase(db); - } - } - - // If that failed, try the XSETTINGS keys... - if (scale_factor <= 0.0) { - scale_factor = X11_GetXsettingsIntKey(_this, "Gdk/WindowScalingFactor", -1); - - // The Xft/DPI key is stored in increments of 1024th - if (scale_factor <= 0.0) { - int dpi = X11_GetXsettingsIntKey(_this, "Xft/DPI", -1); - if (dpi > 0) { - scale_factor = (double) dpi / 1024.0; - scale_factor /= 96.0; + // Get the value of Xft.dpi from the Database + if (X11_XrmGetResource(db, "Xft.dpi", "String", &type, &value)) { + if (value.addr && type && SDL_strcmp(type, "String") == 0) { + int dpi = SDL_atoi(value.addr); + scale_factor = dpi / 96.0; } } - } + X11_XrmDestroyDatabase(db); - // If that failed, try the GDK_SCALE envvar... - if (scale_factor <= 0.0) { - const char *scale_str = SDL_getenv("GDK_SCALE"); - if (scale_str) { - scale_factor = SDL_atoi(scale_str); + if (owns_resource_manager) { + X11_XFree(resource_manager); } } + } - // Nothing or a bad value, just fall back to 1.0 + // If that failed, try the XSETTINGS keys... + if (scale_factor <= 0.0) { + scale_factor = X11_GetXsettingsIntKey(_this, "Gdk/WindowScalingFactor", -1); + + // The Xft/DPI key is stored in increments of 1024th if (scale_factor <= 0.0) { - scale_factor = 1.0; + int dpi = X11_GetXsettingsIntKey(_this, "Xft/DPI", -1); + if (dpi > 0) { + scale_factor = (double) dpi / 1024.0; + scale_factor /= 96.0; + } } } + // If that failed, try the GDK_SCALE envvar... + if (scale_factor <= 0.0) { + const char *scale_str = SDL_getenv("GDK_SCALE"); + if (scale_str) { + scale_factor = SDL_atoi(scale_str); + } + } + + // Nothing or a bad value, just fall back to 1.0 + if (scale_factor <= 0.0) { + scale_factor = 1.0; + } + return (float)scale_factor; } @@ -238,7 +243,96 @@ SDL_PixelFormat X11_GetPixelFormatFromVisualInfo(Display *display, XVisualInfo * return SDL_PIXELFORMAT_UNKNOWN; } +static SDL_DisplayID X11_AddGenericDisplay(SDL_VideoDevice *_this, bool send_event) +{ + // !!! FIXME: a lot of copy/paste from X11_InitModes_XRandR in this function. + SDL_VideoData *data = _this->internal; + Display *dpy = data->display; + const int default_screen = DefaultScreen(dpy); + Screen *screen = ScreenOfDisplay(dpy, default_screen); + int scanline_pad, n, i; + SDL_DisplayModeData *modedata; + SDL_DisplayData *displaydata; + SDL_DisplayMode mode; + XPixmapFormatValues *pixmapformats; + Uint32 pixelformat; + XVisualInfo vinfo; + SDL_VideoDisplay display; + + // note that generally even if you have a multiple physical monitors, ScreenCount(dpy) still only reports ONE screen. + + if (!get_visualinfo(dpy, default_screen, &vinfo)) { + return SDL_SetError("Failed to find an X11 visual for the primary display"); + } + + pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo); + if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) { + return SDL_SetError("Palettized video modes are no longer supported"); + } + + SDL_zero(mode); + mode.w = WidthOfScreen(screen); + mode.h = HeightOfScreen(screen); + mode.format = pixelformat; + + displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata)); + if (!displaydata) { + return false; + } + + modedata = (SDL_DisplayModeData *)SDL_calloc(1, sizeof(SDL_DisplayModeData)); + if (!modedata) { + SDL_free(displaydata); + return false; + } + mode.internal = modedata; + + displaydata->screen = default_screen; + displaydata->visual = vinfo.visual; + displaydata->depth = vinfo.depth; + + scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8; + pixmapformats = X11_XListPixmapFormats(dpy, &n); + if (pixmapformats) { + for (i = 0; i < n; ++i) { + if (pixmapformats[i].depth == vinfo.depth) { + scanline_pad = pixmapformats[i].scanline_pad; + break; + } + } + X11_XFree(pixmapformats); + } + + displaydata->scanline_pad = scanline_pad; + displaydata->x = 0; + displaydata->y = 0; + displaydata->use_xrandr = false; + + SDL_zero(display); + display.name = (char *)"Generic X11 Display"; /* this is just copied and thrown away, it's safe to cast to char* here. */ + display.desktop_mode = mode; + display.internal = displaydata; + display.content_scale = X11_GetGlobalContentScale(_this); + return SDL_AddVideoDisplay(&display, send_event); +} + #ifdef SDL_VIDEO_DRIVER_X11_XRANDR + +static void X11_RemoveGenericDisplay(SDL_VideoDevice *_this) +{ + SDL_DisplayID *displays = SDL_GetDisplays(NULL); + if (displays) { + for (int i = 0; displays[i]; ++i) { + SDL_VideoDisplay *display = SDL_GetVideoDisplay(displays[i]); + const SDL_DisplayData *displaydata = display->internal; + if (!displaydata->xrandr_output) { + SDL_DelVideoDisplay(displays[i], true); + } + } + SDL_free(displays); + } +} + static bool CheckXRandR(Display *display, int *major, int *minor) { // Default the extension not available @@ -505,7 +599,7 @@ static bool X11_FillXRandRDisplayInfo(SDL_VideoDevice *_this, Display *dpy, int display->name = display_name; } display->desktop_mode = mode; - display->content_scale = GetGlobalContentScale(_this); + display->content_scale = X11_GetGlobalContentScale(_this); display->internal = displaydata; return true; @@ -520,10 +614,17 @@ static bool X11_AddXRandRDisplay(SDL_VideoDevice *_this, Display *dpy, int scree return true; // failed to query data, skip this display } - if (SDL_AddVideoDisplay(&display, send_event) == 0) { + SDL_DisplayID displayID = SDL_AddVideoDisplay(&display, false); + if (displayID == 0) { return false; } + // We added an XRandR display, remove the generic display, if any + X11_RemoveGenericDisplay(_this); + + if (send_event) { + SDL_SendDisplayEvent(SDL_GetVideoDisplay(displayID), SDL_EVENT_DISPLAY_ADDED, 0, 0); + } return true; } @@ -587,7 +688,7 @@ static void X11_CheckDisplaysMoved(SDL_VideoDevice *_this, Display *dpy) for (int i = 0; displays[i]; ++i) { SDL_VideoDisplay *display = SDL_GetVideoDisplay(displays[i]); const SDL_DisplayData *displaydata = display->internal; - if (displaydata->screen == screen) { + if (displaydata->xrandr_output && displaydata->screen == screen) { X11_UpdateXRandRDisplay(_this, dpy, screen, displaydata->xrandr_output, res, display); } } @@ -633,8 +734,12 @@ static void X11_CheckDisplaysRemoved(SDL_VideoDevice *_this, Display *dpy) for (int i = 0; i < num_displays; ++i) { if (displays[i]) { - // This display wasn't in the XRandR list - SDL_DelVideoDisplay(displays[i], true); + SDL_VideoDisplay *display = SDL_GetVideoDisplay(displays[i]); + const SDL_DisplayData *displaydata = display->internal; + if (displaydata->xrandr_output) { + // This display wasn't in the XRandR list + SDL_DelVideoDisplay(displays[i], true); + } } } SDL_free(displays); @@ -668,7 +773,17 @@ static void X11_HandleXRandROutputChange(SDL_VideoDevice *_this, const XRROutput if (ev->connection == RR_Disconnected) { // output is going away if (display) { + // Add the generic display if we're about to remove the last XRandR display + SDL_DisplayID generic_display = 0; + if (_this->num_displays == 1) { + generic_display = X11_AddGenericDisplay(_this, false); + } + SDL_DelVideoDisplay(display->id, true); + + if (generic_display) { + SDL_SendDisplayEvent(SDL_GetVideoDisplay(generic_display), SDL_EVENT_DISPLAY_ADDED, 0, 0); + } } X11_CheckDisplaysMoved(_this, ev->display); @@ -808,75 +923,7 @@ static bool X11_InitModes_XRandR(SDL_VideoDevice *_this) enumerate the current displays and their current sizes. */ static bool X11_InitModes_StdXlib(SDL_VideoDevice *_this) { - // !!! FIXME: a lot of copy/paste from X11_InitModes_XRandR in this function. - SDL_VideoData *data = _this->internal; - Display *dpy = data->display; - const int default_screen = DefaultScreen(dpy); - Screen *screen = ScreenOfDisplay(dpy, default_screen); - int scanline_pad, n, i; - SDL_DisplayModeData *modedata; - SDL_DisplayData *displaydata; - SDL_DisplayMode mode; - XPixmapFormatValues *pixmapformats; - Uint32 pixelformat; - XVisualInfo vinfo; - SDL_VideoDisplay display; - - // note that generally even if you have a multiple physical monitors, ScreenCount(dpy) still only reports ONE screen. - - if (!get_visualinfo(dpy, default_screen, &vinfo)) { - return SDL_SetError("Failed to find an X11 visual for the primary display"); - } - - pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo); - if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) { - return SDL_SetError("Palettized video modes are no longer supported"); - } - - SDL_zero(mode); - mode.w = WidthOfScreen(screen); - mode.h = HeightOfScreen(screen); - mode.format = pixelformat; - - displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata)); - if (!displaydata) { - return false; - } - - modedata = (SDL_DisplayModeData *)SDL_calloc(1, sizeof(SDL_DisplayModeData)); - if (!modedata) { - SDL_free(displaydata); - return false; - } - mode.internal = modedata; - - displaydata->screen = default_screen; - displaydata->visual = vinfo.visual; - displaydata->depth = vinfo.depth; - - scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8; - pixmapformats = X11_XListPixmapFormats(dpy, &n); - if (pixmapformats) { - for (i = 0; i < n; ++i) { - if (pixmapformats[i].depth == vinfo.depth) { - scanline_pad = pixmapformats[i].scanline_pad; - break; - } - } - X11_XFree(pixmapformats); - } - - displaydata->scanline_pad = scanline_pad; - displaydata->x = 0; - displaydata->y = 0; - displaydata->use_xrandr = false; - - SDL_zero(display); - display.name = (char *)"Generic X11 Display"; /* this is just copied and thrown away, it's safe to cast to char* here. */ - display.desktop_mode = mode; - display.internal = displaydata; - display.content_scale = GetGlobalContentScale(_this); - if (SDL_AddVideoDisplay(&display, true) == 0) { + if (X11_AddGenericDisplay(_this, true) == 0) { return false; } return true; diff --git a/src/video/x11/SDL_x11modes.h b/src/video/x11/SDL_x11modes.h index 35fd86621b..77f445ace7 100644 --- a/src/video/x11/SDL_x11modes.h +++ b/src/video/x11/SDL_x11modes.h @@ -62,6 +62,8 @@ extern SDL_PixelFormat X11_GetPixelFormatFromVisualInfo(Display *display, XVisua extern bool X11_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect); extern bool X11_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect); +extern float X11_GetGlobalContentScale(SDL_VideoDevice *_this); + #ifdef SDL_VIDEO_DRIVER_X11_XRANDR extern void X11_HandleXRandREvent(SDL_VideoDevice *_this, const XEvent *xevent); #endif diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index 6cfe1c0501..8b468675f6 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -536,8 +536,10 @@ void X11_QuitMouse(SDL_VideoDevice *_this) int j; for (j = 0; j < SDL_arraysize(sys_cursors); j++) { - X11_FreeCursor(sys_cursors[j]); - sys_cursors[j] = NULL; + if (sys_cursors[j]) { + X11_FreeCursor(sys_cursors[j]); + sys_cursors[j] = NULL; + } } for (i = data->mouse_device_info; i; i = next) { diff --git a/src/video/x11/SDL_x11mouse.h b/src/video/x11/SDL_x11mouse.h index 2a2973c3d7..db6f00c4eb 100644 --- a/src/video/x11/SDL_x11mouse.h +++ b/src/video/x11/SDL_x11mouse.h @@ -26,6 +26,7 @@ typedef struct SDL_XInput2DeviceInfo { int device_id; + int number[2]; bool relative[2]; double minval[2]; double maxval[2]; diff --git a/src/video/x11/SDL_x11settings.c b/src/video/x11/SDL_x11settings.c index a1a9846d28..50bf773f3a 100644 --- a/src/video/x11/SDL_x11settings.c +++ b/src/video/x11/SDL_x11settings.c @@ -26,65 +26,28 @@ #include "SDL_x11video.h" #include "SDL_x11settings.h" -#include "core/unix/SDL_gtk.h" - #define SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR "Gdk/WindowScalingFactor" +#define SDL_XSETTINGS_GDK_UNSCALED_DPI "Gdk/UnscaledDPI" #define SDL_XSETTINGS_XFT_DPI "Xft/DPI" -static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data) +static void UpdateContentScale(SDL_VideoDevice *_this) { - SDL_VideoDevice *_this = data; - float scale_factor = 1.0; - int i; - - if (SDL_strcmp(name, SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR) != 0 || - SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) != 0) { - return; - } - - if (setting->type != XSETTINGS_TYPE_INT) { - return; - } - - switch (action) { - case XSETTINGS_ACTION_NEW: - SDL_FALLTHROUGH; - case XSETTINGS_ACTION_CHANGED: - scale_factor = setting->data.v_int; - if (SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) == 0) { - scale_factor = scale_factor / 1024.0f / 96.0f; - } - break; - case XSETTINGS_ACTION_DELETED: - scale_factor = 1.0; - break; - } - if (_this) { - for (i = 0; i < _this->num_displays; ++i) { + float scale_factor = X11_GetGlobalContentScale(_this); + for (int i = 0; i < _this->num_displays; ++i) { SDL_SetDisplayContentScale(_this->displays[i], scale_factor); } } } -static void OnGtkXftDpi(GtkSettings *settings, GParamSpec *pspec, gpointer ptr) +static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data) { - SDL_VideoDevice *_this = (SDL_VideoDevice *)ptr; + SDL_VideoDevice *_this = data; - SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); - if (gtk) { - int dpi = 0; - gtk->g.object_get(settings, "gtk-xft-dpi", &dpi, NULL); - - if (dpi != 0) { - float scale_factor = dpi / 1024.f / 96.f; - - for (int i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = _this->displays[i]; - SDL_SetDisplayContentScale(display, scale_factor); - } - } - SDL_Gtk_ExitContext(gtk); + if (SDL_strcmp(name, SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR) == 0 || + SDL_strcmp(name, SDL_XSETTINGS_GDK_UNSCALED_DPI) == 0 || + SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) == 0) { + UpdateContentScale(_this); } } @@ -93,28 +56,8 @@ void X11_InitXsettings(SDL_VideoDevice *_this) SDL_VideoData *data = _this->internal; SDLX11_SettingsData *xsettings_data = &data->xsettings_data; - GtkSettings *gtksettings = NULL; - guint xft_dpi_signal_handler_id = 0; - - SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); - if (gtk) { - // Prefer to listen for DPI changes from gtk. In XWayland this is necessary as XSettings - // are not updated dynamically. - gtksettings = gtk->gtk.settings_get_default(); - if (gtksettings) { - xft_dpi_signal_handler_id = gtk->g.signal_connect(gtksettings, "notify::gtk-xft-dpi", &OnGtkXftDpi, _this); - } - SDL_Gtk_ExitContext(gtk); - } - - if (gtksettings && xft_dpi_signal_handler_id) { - xsettings_data->gtksettings = gtksettings; - xsettings_data->xft_dpi_signal_handler_id = xft_dpi_signal_handler_id; - } else { - xsettings_data->xsettings = xsettings_client_new(data->display, - DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this); - } - + xsettings_data->xsettings = xsettings_client_new(data->display, + DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this); } void X11_QuitXsettings(SDL_VideoDevice *_this) @@ -124,29 +67,17 @@ void X11_QuitXsettings(SDL_VideoDevice *_this) if (xsettings_data->xsettings) { xsettings_client_destroy(xsettings_data->xsettings); + xsettings_data->xsettings = NULL; } - - SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); - if (gtk) { - if (xsettings_data->gtksettings && xsettings_data->xft_dpi_signal_handler_id) { - gtk->g.signal_handler_disconnect(xsettings_data->gtksettings, xsettings_data->xft_dpi_signal_handler_id); - } - SDL_Gtk_ExitContext(gtk); - } - - SDL_zero(xsettings_data); } -void X11_HandleXsettings(SDL_VideoDevice *_this, const XEvent *xevent) +void X11_HandleXsettingsEvent(SDL_VideoDevice *_this, const XEvent *xevent) { SDL_VideoData *data = _this->internal; SDLX11_SettingsData *xsettings_data = &data->xsettings_data; if (xsettings_data->xsettings) { - if (!xsettings_client_process_event(xsettings_data->xsettings, xevent)) { - xsettings_client_destroy(xsettings_data->xsettings); - xsettings_data->xsettings = NULL; - } + xsettings_client_process_event(xsettings_data->xsettings, xevent); } } diff --git a/src/video/x11/SDL_x11settings.h b/src/video/x11/SDL_x11settings.h index 39926b66c6..f91ed70ac7 100644 --- a/src/video/x11/SDL_x11settings.h +++ b/src/video/x11/SDL_x11settings.h @@ -27,17 +27,13 @@ #include #include "xsettings-client.h" -#include "core/unix/SDL_gtk.h" - typedef struct X11_SettingsData { XSettingsClient *xsettings; - GtkSettings *gtksettings; - guint xft_dpi_signal_handler_id; } SDLX11_SettingsData; extern void X11_InitXsettings(SDL_VideoDevice *_this); extern void X11_QuitXsettings(SDL_VideoDevice *_this); -extern void X11_HandleXsettings(SDL_VideoDevice *_this, const XEvent *xevent); +extern void X11_HandleXsettingsEvent(SDL_VideoDevice *_this, const XEvent *xevent); extern int X11_GetXsettingsIntKey(SDL_VideoDevice *_this, const char *key, int fallback_value); #endif // SDL_x11settings_h_ diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index df9d59b36e..959aabce8c 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -71,6 +71,7 @@ SDL_X11_SYM(int,XFreePixmap,(Display* a,Pixmap b)) SDL_X11_SYM(void,XFreeStringList,(char** a)) SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b)) SDL_X11_SYM(int,XGetInputFocus,(Display *a,Window *b,int *c)) +SDL_X11_SYM(KeySym*,XGetKeyboardMapping,(Display *a, KeyCode b, int c, int *d)) SDL_X11_SYM(int,XGetErrorDatabaseText,(Display* a,_Xconst char* b,_Xconst char* c,_Xconst char* d,char* e,int f)) SDL_X11_SYM(XModifierKeymap*,XGetModifierMapping,(Display* a)) SDL_X11_SYM(int,XGetPointerControl,(Display* a,int* b,int* c,int* d)) @@ -196,35 +197,21 @@ SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b)) SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b)) #endif -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f)) -#if NeedWidePrototypes -SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, unsigned int b, unsigned int c, unsigned int* d, KeySym* e)) -#else -SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, KeyCode b, unsigned int c, unsigned int* d, KeySym* e)) -#endif +SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a, KeyCode b, unsigned int c, unsigned int d)) +SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned long d)) +SDL_X11_SYM(Bool,XkbSelectEventDetails,(Display* a, unsigned int b, unsigned int c, unsigned long d, unsigned long e)) +SDL_X11_SYM(Status,XkbGetNames,(Display *a, unsigned int b, XkbDescPtr c)) SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c)) SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c)) SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c)) SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c)) SDL_X11_SYM(void,XkbFreeKeyboard,(XkbDescPtr a,unsigned int b, Bool c)) +SDL_X11_SYM(Status,XkbRefreshKeyboardMapping,(XkbMapNotifyEvent *a)) SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c)) #endif -// XKeycodeToKeysym is a deprecated function -#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -#if NeedWidePrototypes -SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,unsigned int b,int c)) -#else -SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,KeyCode b,int c)) -#endif -#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA -#pragma GCC diagnostic pop -#endif - #ifdef X_HAVE_UTF8_STRING SDL_X11_MODULE(UTF8) SDL_X11_SYM(int,Xutf8TextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e)) diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index dd4e635dc2..ce34f9e6e9 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -395,6 +395,7 @@ static bool X11_VideoInit(SDL_VideoDevice *_this) GET_ATOM(SDL_SELECTION); GET_ATOM(TARGETS); GET_ATOM(SDL_FORMATS); + GET_ATOM(RESOURCE_MANAGER); GET_ATOM(XdndAware); GET_ATOM(XdndEnter); GET_ATOM(XdndLeave); @@ -468,6 +469,7 @@ void X11_VideoQuit(SDL_VideoDevice *_this) } #endif + X11_QuitXinput2(_this); X11_QuitModes(_this); X11_QuitKeyboard(_this); X11_QuitMouse(_this); diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index a336a800f5..b5bdb67409 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -24,6 +24,7 @@ #define SDL_x11video_h_ #include "../SDL_sysvideo.h" +#include "../../events/SDL_keymap_c.h" #include "../../core/linux/SDL_dbus.h" #include "../../core/linux/SDL_ime.h" @@ -103,6 +104,7 @@ struct SDL_VideoData Atom SDL_SELECTION; Atom TARGETS; Atom SDL_FORMATS; + Atom RESOURCE_MANAGER; Atom XdndAware; Atom XdndEnter; Atom XdndLeave; @@ -124,7 +126,6 @@ struct SDL_VideoData Atom pen_atom_wacom_tool_type; } atoms; - SDL_Scancode key_layout[256]; bool selection_waiting; bool selection_incr_waiting; @@ -143,21 +144,43 @@ struct SDL_VideoData int xrandr_event_base; struct { -#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM - XkbDescPtr desc_ptr; + bool xkb_enabled; + SDL_Scancode key_layout[256]; + + union + { +#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB + struct + { + XkbDescPtr desc_ptr; + SDL_Keymap *keymaps[XkbNumKbdGroups]; + unsigned long last_map_serial; + int event; + Uint32 current_group; + } xkb; // Modern XKB keyboard handling #endif - int event; - unsigned int current_group; - unsigned int xkb_modifiers; - - SDL_Keymod sdl_modifiers; + struct + { + KeySym *keysym_map; + int keysyms_per_key; + int min_keycode; + int max_keycode; + } core; // Legacy core keyboard handling + }; + Uint32 pressed_modifiers; + Uint32 locked_modifiers; + SDL_Keymod sdl_pressed_modifiers; + SDL_Keymod sdl_physically_pressed_modifiers; + SDL_Keymod sdl_locked_modifiers; + // Virtual modifiers looked up by name. + Uint32 alt_mask; + Uint32 gui_mask; + Uint32 level3_mask; + Uint32 level5_mask; Uint32 numlock_mask; Uint32 scrolllock_mask; - } xkb; - - KeyCode filter_code; - Time filter_time; + } keyboard; #ifdef SDL_VIDEO_VULKAN // Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index b0f8fed6eb..52bec5f91d 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -475,7 +475,7 @@ static void SetupWindowInput(SDL_VideoDevice *_this, SDL_Window *window) } #endif - X11_Xinput2SelectTouch(_this, window); + X11_Xinput2Select(_this, window); { unsigned int x11_keyboard_events = KeyPressMask | KeyReleaseMask; diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index eb212378c6..11afba68ef 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -45,23 +45,66 @@ static bool xinput2_multitouch_supported; * this extension */ static int xinput2_opcode; -static void parse_valuators(const double *input_values, const unsigned char *mask, int mask_len, - double *output_values, int output_values_len) +static Atom xinput2_rel_x_atom; +static Atom xinput2_rel_y_atom; +static Atom xinput2_abs_x_atom; +static Atom xinput2_abs_y_atom; + +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO +typedef struct { - int i = 0, z = 0; - int top = mask_len * 8; - if (top > MAX_AXIS) { - top = MAX_AXIS; + int number; + int scroll_type; + double prev_value; + double increment; + bool prev_value_valid; +} SDL_XInput2ScrollInfo; + +typedef struct +{ + int device_id; + int scroll_info_count; + SDL_XInput2ScrollInfo *scroll_info; +} SDL_XInput2ScrollableDevice; + +static SDL_XInput2ScrollableDevice *scrollable_devices; +static int scrollable_device_count; +static bool xinput2_scrolling_supported; +#endif + +static void parse_relative_valuators(SDL_XInput2DeviceInfo *devinfo, const XIRawEvent *rawev) +{ + double processed_coords[2] = { 0.0, 0.0 }; + int values_i = 0, found = 0; + + for (int i = 0; i < rawev->valuators.mask_len * 8 && found < 2; ++i) { + if (!XIMaskIsSet(rawev->valuators.mask, i)) { + continue; + } + + for (int j = 0; j < 2; ++j) { + if (devinfo->number[j] == i) { + double current_val = rawev->raw_values[values_i]; + + if (devinfo->relative[j]) { + processed_coords[j] = current_val; + } else { + processed_coords[j] = (current_val - devinfo->prev_coords[j]); // convert absolute to relative + devinfo->prev_coords[j] = current_val; + } + ++found; + + break; + } + } + + ++values_i; } - SDL_memset(output_values, 0, output_values_len * sizeof(double)); - for (; i < top && z < output_values_len; i++) { - if (XIMaskIsSet(mask, i)) { - const int value = (int)*input_values; - output_values[z] = value; - input_values++; - } - z++; + // Relative mouse motion is delivered to the window with keyboard focus + SDL_Mouse *mouse = SDL_GetMouse(); + if (mouse->relative_mode && SDL_GetKeyboardFocus()) { + SDL_SendMouseMotion(rawev->time, mouse->focus, (SDL_MouseID)rawev->sourceid, true, (float)processed_coords[0], (float)processed_coords[1]); } } @@ -95,6 +138,62 @@ static SDL_Window *xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window return windowdata ? windowdata->window : NULL; } +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO +static void xinput2_reset_scrollable_valuators(SDL_VideoData *videodata) +{ + for (int i = 0; i < scrollable_device_count; ++i) { + for (int j = 0; j < scrollable_devices[i].scroll_info_count; ++j) { + scrollable_devices[i].scroll_info[j].prev_value_valid = false; + } + } +} + +static void xinput2_parse_scrollable_valuators(const XIDeviceEvent *xev) +{ + for (int i = 0; i < scrollable_device_count; ++i) { + const SDL_XInput2ScrollableDevice *sd = &scrollable_devices[i]; + if (xev->sourceid == sd->device_id) { + int values_i = 0; + for (int j = 0; j < xev->valuators.mask_len * 8; ++j) { + if (!XIMaskIsSet(xev->valuators.mask, j)) { + continue; + } + + for (int k = 0; k < sd->scroll_info_count; ++k) { + SDL_XInput2ScrollInfo *info = &sd->scroll_info[k]; + if (info->number == j) { + const double current_val = xev->valuators.values[values_i]; + const double delta = (info->prev_value - current_val) / info->increment; + /* Ignore very large jumps that can happen as a result of overflowing + * the maximum range, as the driver will reset the position to zero + * at "something that's close to 2^32". + * + * The first scroll event is meaningless by itself and must be discarded, + * as it is only useful for establishing a baseline for future deltas. + * This is a known deficiency of the XInput2 scroll protocol, and, + * unfortunately, there is nothing we can do about it. + * + * http://who-t.blogspot.com/2012/06/xi-21-protocol-design-issues.html + */ + if (info->prev_value_valid && SDL_fabs(delta) < (double)SDL_MAX_SINT32 * 0.95) { + const double x = info->scroll_type == XIScrollTypeHorizontal ? delta : 0; + const double y = info->scroll_type == XIScrollTypeVertical ? delta : 0; + + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_SendMouseWheel(xev->time, mouse->focus, (SDL_MouseID)xev->sourceid, (float)x, (float)y, SDL_MOUSEWHEEL_NORMAL); + } + info->prev_value = current_val; + info->prev_value_valid = true; + } + } + + ++values_i; + } + } + } +} +#endif // SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH static void xinput2_normalize_touch_coordinates(SDL_Window *window, double in_x, double in_y, float *out_x, float *out_y) { @@ -119,6 +218,24 @@ static void xinput2_normalize_touch_coordinates(SDL_Window *window, double in_x, #endif // SDL_VIDEO_DRIVER_X11_XINPUT2 +static bool X11_Xinput2IsMultitouchSupported(void) +{ +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH + return xinput2_initialized && xinput2_multitouch_supported; +#else + return false; +#endif +} + +static bool X11_Xinput2IsScrollingSupported(void) +{ +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + return xinput2_initialized && xinput2_scrolling_supported; +#else + return false; +#endif +} + bool X11_InitXinput2(SDL_VideoDevice *_this) { #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 @@ -126,7 +243,7 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) int version = 0; XIEventMask eventmask; - unsigned char mask[4] = { 0, 0, 0, 0 }; + unsigned char mask[5] = { 0, 0, 0, 0, 0 }; int event, err; /* XInput2 is required for relative mouse mode, so you probably want to leave this enabled */ @@ -156,10 +273,20 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) xinput2_initialized = true; +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO // Smooth scrolling needs XInput 2.1 + xinput2_scrolling_supported = xinput2_version_atleast(version, 2, 1); +#endif + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH // Multitouch needs XInput 2.2 xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2); #endif + // Populate the atoms for finding relative axes + xinput2_rel_x_atom = X11_XInternAtom(data->display, "Rel X", False); + xinput2_rel_y_atom = X11_XInternAtom(data->display, "Rel Y", False); + xinput2_abs_x_atom = X11_XInternAtom(data->display, "Abs X", False); + xinput2_abs_y_atom = X11_XInternAtom(data->display, "Abs Y", False); + // Enable raw motion events for this display SDL_zero(eventmask); SDL_zeroa(mask); @@ -171,6 +298,12 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) XISetMask(mask, XI_RawButtonPress); XISetMask(mask, XI_RawButtonRelease); +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + if (X11_Xinput2IsScrollingSupported()) { + XISetMask(mask, XI_Motion); + } +#endif + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH // Enable raw touch events if supported if (X11_Xinput2IsMultitouchSupported()) { @@ -199,6 +332,18 @@ bool X11_InitXinput2(SDL_VideoDevice *_this) #endif } +void X11_QuitXinput2(SDL_VideoDevice *_this) +{ +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + for (int i = 0; i < scrollable_device_count; ++i) { + SDL_free(scrollable_devices[i].scroll_info); + } + SDL_free(scrollable_devices); + scrollable_devices = NULL; + scrollable_device_count = 0; +#endif +} + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2 // xi2 device went away? take it out of the list. static void xinput2_remove_device_info(SDL_VideoData *videodata, const int device_id) @@ -227,7 +372,6 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata, SDL_XInput2DeviceInfo *prev = NULL; SDL_XInput2DeviceInfo *devinfo; XIDeviceInfo *xidevinfo; - int axis = 0; int i; for (devinfo = videodata->mouse_device_info; devinfo; devinfo = devinfo->next) { @@ -257,18 +401,49 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata, devinfo->device_id = device_id; - /* !!! FIXME: this is sort of hacky because we only care about the first two axes we see, but any given - !!! FIXME: axis could be relative or absolute, and they might not even be the X and Y axes! - !!! FIXME: But we go on, for now. Maybe we need a more robust mouse API in SDL3... */ + /* Search for relative axes with the following priority: + * - Labelled 'Rel X'/'Rel Y' + * - Labelled 'Abs X'/'Abs Y' + * - The first two axes found + */ + bool have_rel_x = false, have_rel_y = false; + bool have_abs_x = false, have_abs_y = false; + int axis_index = 0; for (i = 0; i < xidevinfo->num_classes; i++) { const XIValuatorClassInfo *v = (const XIValuatorClassInfo *)xidevinfo->classes[i]; if (v->type == XIValuatorClass) { - devinfo->relative[axis] = (v->mode == XIModeRelative); - devinfo->minval[axis] = v->min; - devinfo->maxval[axis] = v->max; - if (++axis >= 2) { + if (v->label == xinput2_rel_x_atom || (v->label == xinput2_abs_x_atom && !have_rel_x) || + (axis_index == 0 && !have_rel_x && !have_abs_x)) { + devinfo->number[0] = v->number; + devinfo->relative[0] = (v->mode == XIModeRelative); + devinfo->minval[0] = v->min; + devinfo->maxval[0] = v->max; + + if (v->label == xinput2_rel_x_atom) { + have_rel_x = true; + } else if (v->label == xinput2_abs_x_atom) { + have_abs_x = true; + } + } else if (v->label == xinput2_rel_y_atom || (v->label == xinput2_abs_y_atom && !have_rel_y) || + (axis_index == 1 && !have_rel_y && !have_abs_y)) { + devinfo->number[1] = v->number; + devinfo->relative[1] = (v->mode == XIModeRelative); + devinfo->minval[1] = v->min; + devinfo->maxval[1] = v->max; + + if (v->label == xinput2_rel_y_atom) { + have_rel_y = true; + } else if (v->label == xinput2_abs_y_atom) { + have_abs_y = true; + } + } + + // If two relative axes were found, nothing more to do. + if (have_rel_x && have_rel_y) { break; } + + ++axis_index; } } @@ -319,41 +494,18 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) { const XIRawEvent *rawev = (const XIRawEvent *)cookie->data; const bool is_pen = X11_FindPenByDeviceID(rawev->sourceid) != NULL; - SDL_Mouse *mouse = SDL_GetMouse(); - SDL_XInput2DeviceInfo *devinfo; - double coords[2]; - double processed_coords[2]; - int i; - Uint64 timestamp = X11_GetEventTimestamp(rawev->time); videodata->global_mouse_changed = true; if (is_pen) { break; // Pens check for XI_Motion instead } - devinfo = xinput2_get_device_info(videodata, rawev->deviceid); + SDL_XInput2DeviceInfo *devinfo = xinput2_get_device_info(videodata, rawev->deviceid); if (!devinfo) { break; // oh well. } - parse_valuators(rawev->raw_values, rawev->valuators.mask, - rawev->valuators.mask_len, coords, 2); - - for (i = 0; i < 2; i++) { - if (devinfo->relative[i]) { - processed_coords[i] = coords[i]; - } else { - processed_coords[i] = devinfo->prev_coords[i] - coords[i]; // convert absolute to relative - } - } - - // Relative mouse motion is delivered to the window with keyboard focus - if (mouse->relative_mode && SDL_GetKeyboardFocus()) { - SDL_SendMouseMotion(timestamp, mouse->focus, (SDL_MouseID)rawev->sourceid, true, (float)processed_coords[0], (float)processed_coords[1]); - } - - devinfo->prev_coords[0] = coords[0]; - devinfo->prev_coords[1] = coords[1]; + parse_relative_valuators(devinfo, rawev); } break; case XI_KeyPress: @@ -409,6 +561,11 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) X11_PenHandle *pen = X11_FindPenByDeviceID(xev->sourceid); const int button = xev->detail; const bool down = (cookie->evtype == XI_ButtonPress); +#if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH) + bool pointer_emulated = (xev->flags & XIPointerEmulated) != 0; +#else + bool pointer_emulated = false; +#endif if (pen) { if (xev->deviceid != xev->sourceid) { @@ -429,8 +586,12 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) /* Discard wheel events from "Master" devices to avoid duplicates, * as coarse wheel events are stateless and can't be deduplicated. + * + * If the pointer emulation flag is set on a wheel event, it is being + * emulated from a scroll valuator, which will be handled natively. */ - if (xev->deviceid != xev->sourceid && X11_IsWheelEvent(button, &x_ticks, &y_ticks)) { + if ((pointer_emulated || xev->deviceid != xev->sourceid) && + X11_IsWheelEvent(button, &x_ticks, &y_ticks)) { break; } @@ -443,13 +604,19 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) } } break; +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + case XI_Enter: + xinput2_reset_scrollable_valuators(videodata); + break; +#endif + /* Register to receive XI_Motion (which deactivates MotionNotify), so that we can distinguish real mouse motions from synthetic ones, for multitouch and pen support. */ case XI_Motion: { const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data; -#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH - bool pointer_emulated = ((xev->flags & XIPointerEmulated) != 0); +#if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH) + bool pointer_emulated = (xev->flags & XIPointerEmulated) != 0; #else bool pointer_emulated = false; #endif @@ -475,14 +642,22 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie) SDL_SendPenAxis(0, pen->pen, window, (SDL_PenAxis) i, axes[i]); } } - } else if (!pointer_emulated && xev->deviceid == videodata->xinput_master_pointer_device) { - // Use the master device for non-relative motion, as the slave devices can seemingly lag behind. - SDL_Mouse *mouse = SDL_GetMouse(); - if (!mouse->relative_mode) { - SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); - if (window) { - X11_ProcessHitTest(_this, window->internal, (float)xev->event_x, (float)xev->event_y, false); - SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, (float)xev->event_x, (float)xev->event_y); + } else if (!pointer_emulated) { +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + if (xev->deviceid == xev->sourceid) { + xinput2_parse_scrollable_valuators(xev); + } +#endif + + if (xev->deviceid == videodata->xinput_master_pointer_device) { + // Use the master device for non-relative motion, as the slave devices can seemingly lag behind. + SDL_Mouse *mouse = SDL_GetMouse(); + if (!mouse->relative_mode) { + SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event); + if (window) { + X11_ProcessHitTest(_this, window->internal, (float)xev->event_x, (float)xev->event_y, false); + SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, (float)xev->event_x, (float)xev->event_y); + } } } } @@ -524,29 +699,36 @@ void X11_InitXinput2Multitouch(SDL_VideoDevice *_this) { } -void X11_Xinput2SelectTouch(SDL_VideoDevice *_this, SDL_Window *window) +void X11_Xinput2Select(SDL_VideoDevice *_this, SDL_Window *window) { -#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH - SDL_VideoData *data = NULL; +#if defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO) || defined(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH) + SDL_VideoData *data = _this->internal; + SDL_WindowData *window_data = window->internal; XIEventMask eventmask; - unsigned char mask[4] = { 0, 0, 0, 0 }; - SDL_WindowData *window_data = NULL; + unsigned char mask[5] = { 0, 0, 0, 0, 0 }; - if (!X11_Xinput2IsMultitouchSupported()) { + if (!X11_Xinput2IsScrollingSupported() && !X11_Xinput2IsMultitouchSupported()) { return; } - data = _this->internal; - window_data = window->internal; - eventmask.deviceid = XIAllMasterDevices; eventmask.mask_len = sizeof(mask); eventmask.mask = mask; - XISetMask(mask, XI_TouchBegin); - XISetMask(mask, XI_TouchUpdate); - XISetMask(mask, XI_TouchEnd); - XISetMask(mask, XI_Motion); + if (X11_Xinput2IsScrollingSupported()) { + /* Track enter events that inform us that we need to update + * the previous scroll coordinates since we cannot track + * them outside our window. + */ + XISetMask(mask, XI_Enter); + } + + if (X11_Xinput2IsMultitouchSupported()) { + XISetMask(mask, XI_TouchBegin); + XISetMask(mask, XI_TouchUpdate); + XISetMask(mask, XI_TouchEnd); + XISetMask(mask, XI_Motion); + } X11_XISelectEvents(data->display, window_data->xwindow, &eventmask, 1); #endif @@ -610,15 +792,6 @@ bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *windo return false; } -bool X11_Xinput2IsMultitouchSupported(void) -{ -#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH - return xinput2_initialized && xinput2_multitouch_supported; -#else - return true; -#endif -} - void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window) { #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @@ -748,6 +921,16 @@ void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this, bool initial_check) old_mice = SDL_GetMice(&old_mouse_count); old_touch_devices = SDL_GetTouchDevices(&old_touch_count); +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + // Scroll devices don't get add/remove events, so just rebuild the list. + for (int i = 0; i < scrollable_device_count; ++i) { + SDL_free(scrollable_devices[i].scroll_info); + } + SDL_free(scrollable_devices); + scrollable_devices = NULL; + scrollable_device_count = 0; +#endif + for (int i = 0; i < ndevices; i++) { XIDeviceInfo *dev = &info[i]; @@ -778,6 +961,54 @@ void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this, bool initial_check) break; } +#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO + SDL_XInput2ScrollableDevice *sd = NULL; + int allocated_scroll_info_count = 0; + + for (int j = 0; j < dev->num_classes; j++) { + const XIAnyClassInfo *class = dev->classes[j]; + const XIScrollClassInfo *s = (XIScrollClassInfo *)class; + + if (class->type != XIScrollClass) { + continue; + } + + // Allocate a new scrollable device. + if (!sd) { + scrollable_devices = SDL_realloc(scrollable_devices, (scrollable_device_count + 1) * sizeof(SDL_XInput2ScrollableDevice)); + if (!scrollable_devices) { + // No memory; so just skip this. + break; + } + + sd = &scrollable_devices[scrollable_device_count]; + ++scrollable_device_count; + + SDL_zerop(sd); + sd->device_id = dev->deviceid; + } + + // Allocate new scroll info entries two at a time, as they typically come in a horizontal/vertical pair. + if (sd->scroll_info_count == allocated_scroll_info_count) { + sd->scroll_info = SDL_realloc(sd->scroll_info, (allocated_scroll_info_count + 2) * sizeof(SDL_XInput2ScrollInfo)); + if (!sd->scroll_info) { + // No memory; just skip this. + break; + } + + allocated_scroll_info_count += 2; + } + + SDL_XInput2ScrollInfo *scroll_info = &sd->scroll_info[sd->scroll_info_count]; + ++sd->scroll_info_count; + + SDL_zerop(scroll_info); + scroll_info->number = s->number; + scroll_info->scroll_type = s->scroll_type; + scroll_info->increment = s->increment; + } +#endif + #ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH for (int j = 0; j < dev->num_classes; j++) { Uint64 touchID; diff --git a/src/video/x11/SDL_x11xinput2.h b/src/video/x11/SDL_x11xinput2.h index c96c020bc7..35f4bb8b8b 100644 --- a/src/video/x11/SDL_x11xinput2.h +++ b/src/video/x11/SDL_x11xinput2.h @@ -31,11 +31,11 @@ typedef struct XGenericEventCookie XGenericEventCookie; #endif extern bool X11_InitXinput2(SDL_VideoDevice *_this); +extern void X11_QuitXinput2(SDL_VideoDevice *_this); extern void X11_InitXinput2Multitouch(SDL_VideoDevice *_this); extern void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie); extern bool X11_Xinput2IsInitialized(void); -extern bool X11_Xinput2IsMultitouchSupported(void); -extern void X11_Xinput2SelectTouch(SDL_VideoDevice *_this, SDL_Window *window); +extern void X11_Xinput2Select(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window); extern void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window); extern bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window); diff --git a/test/testautomation_rect.c b/test/testautomation_rect.c index fa5c52ccea..7f7e4eb6ee 100644 --- a/test/testautomation_rect.c +++ b/test/testautomation_rect.c @@ -916,7 +916,7 @@ static int SDLCALL rect_testIntersectRectEmpty(void *arg) */ static int SDLCALL rect_testIntersectRectParam(void *arg) { - SDL_Rect rectA; + SDL_Rect rectA = { 0 }; SDL_Rect rectB = { 0 }; SDL_Rect result; bool intersection; @@ -1165,7 +1165,7 @@ static int SDLCALL rect_testHasIntersectionEmpty(void *arg) */ static int SDLCALL rect_testHasIntersectionParam(void *arg) { - SDL_Rect rectA; + SDL_Rect rectA = { 0 }; SDL_Rect rectB = { 0 }; bool intersection; @@ -1726,7 +1726,7 @@ static int SDLCALL rect_testUnionRectInside(void *arg) */ static int SDLCALL rect_testUnionRectParam(void *arg) { - SDL_Rect rectA, rectB = { 0 }; + SDL_Rect rectA = { 0 }, rectB = { 0 }; SDL_Rect result; /* invalid parameter combinations */ diff --git a/test/testgles2.c b/test/testgles2.c index 1184eab7cb..ba3e0ddcda 100644 --- a/test/testgles2.c +++ b/test/testgles2.c @@ -19,7 +19,7 @@ #include -#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_LINUX) +#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_HURD) #define HAVE_OPENGLES2 #endif