Skip to content

Commit

Permalink
Update SDL2 bindings to release 2.24.0 (py-sdl#246)
Browse files Browse the repository at this point in the history
* Update bindings for 2.24.0

* Update CI runners for 2.24.0

* Fix silly _create_window bug

* Try fixing renderer tests w/ dummy on Windows

* Try workaround for weird ctypes issue

* Update news.rst
  • Loading branch information
a-hurst authored Sep 2, 2022
1 parent 1a51888 commit ca440b9
Show file tree
Hide file tree
Showing 17 changed files with 253 additions and 88 deletions.
4 changes: 2 additions & 2 deletions .ci/getsdl2.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
}

libversions = {
'2.0.22.post1': { # NOTE: Temporary until SDL2 2.24.0 is released
'SDL2': '2.0.22',
'2.24.0': {
'SDL2': '2.24.0',
'SDL2_mixer': '2.6.0',
'SDL2_ttf': '2.20.0',
'SDL2_image': '2.6.0',
Expand Down
29 changes: 18 additions & 11 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@ jobs:
fail-fast: false
matrix:
python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10']
sdl2: ['2.0.22']
sdl2: ['2.24.0']
name-prefix: ['Linux (Python ']
include:
- python-version: 'pypy-2.7'
sdl2: '2.0.22'
sdl2: '2.24.0'
name-prefix: 'Experimental / Linux ('
- python-version: 'pypy-3.7'
sdl2: '2.0.22'
sdl2: '2.24.0'
name-prefix: 'Experimental / Linux ('

env:
PYSDL2_DLL_VERSION: ${{ matrix.sdl2 }}
SDL_VIDEODRIVER: dummy
SDL_AUDIODRIVER: dummy
SDL_RENDER_DRIVER: software
Expand All @@ -51,7 +52,7 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install numpy pytest pillow
python -m pip install pysdl2-dll
python -m pip install pysdl2-dll==$PYSDL2_DLL_VERSION
- name: Install and test PySDL2
run: |
Expand All @@ -71,11 +72,11 @@ jobs:
fail-fast: false
matrix:
python-version: [3.9]
sdl2: ['2.0.22.post1', '2.0.20', '2.0.16']
sdl2: ['2.24.0', '2.0.22', '2.0.20']
name-prefix: ['macOS (Python ']
include:
- python-version: '2.7'
sdl2: '2.0.22.post1'
sdl2: '2.24.0'
name-prefix: 'macOS (Python '
- python-version: '3.9'
sdl2: 'from Homebrew'
Expand Down Expand Up @@ -127,21 +128,27 @@ jobs:
matrix:
python-version: [3.9]
architecture: ['x64']
sdl2: ['2.0.22.post1', '2.0.20', '2.0.18', '2.0.16', '2.0.14', '2.0.12',
'2.0.10', '2.0.9', '2.0.8', '2.0.7', '2.0.6', '2.0.5']
sdl2: [
'2.24.0', '2.0.22', '2.0.20', '2.0.18', '2.0.16', '2.0.14', '2.0.12',
'2.0.10', '2.0.9', '2.0.8', '2.0.7', '2.0.6', '2.0.5'
]
name-prefix: ['Windows (Python ']
include:
- python-version: '2.7'
architecture: 'x64'
sdl2: '2.0.22.post1'
sdl2: '2.24.0'
name-prefix: 'Windows (Python '
- python-version: '2.7'
architecture: 'x86'
sdl2: '2.0.22.post1'
sdl2: '2.24.0'
name-prefix: 'Windows 32-bit (Python '
- python-version: '3.9'
architecture: 'x86'
sdl2: '2.0.22.post1'
sdl2: '2.24.0'
name-prefix: 'Windows 32-bit (Python '
- python-version: '2.7'
architecture: 'x86'
sdl2: '2.0.22'
name-prefix: 'Windows 32-bit (Python '
- python-version: '2.7'
architecture: 'x86'
Expand Down
6 changes: 6 additions & 0 deletions doc/news.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ New Features:
individually using keyword arguments (e.g. ``sdl2.ext.init(audio=True)`` to
initialize the audio subsystem as well as the default video subsystem).
Previously, this function only initailized the video subsystem.
* Updated to wrap new functions and constants in SDL2 2.24.0 (PR #246).

Fixed Bugs:

* Fixed broken behaviour (and potential segfaults) with usage of
:func:`sdl2.SDL_GUIDToString` on Python 3.6 and older (PR #246).


0.9.13
Expand Down
5 changes: 5 additions & 0 deletions sdl2/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ class SDL_AudioStream(c_void_p):
SDLFunc("SDL_GetNumAudioDevices", [c_int], c_int),
SDLFunc("SDL_GetAudioDeviceName", [c_int, c_int], c_char_p),
SDLFunc("SDL_GetAudioDeviceSpec", [c_int, c_int, _P(SDL_AudioSpec)], c_int, added='2.0.16'),
SDLFunc("SDL_GetDefaultAudioInfo",
[_P(c_char_p), _P(SDL_AudioSpec), c_int],
returns = c_int, added = '2.24.0'
),
SDLFunc("SDL_OpenAudioDevice",
[c_char_p, c_int, _P(SDL_AudioSpec), _P(SDL_AudioSpec), c_int],
returns = SDL_AudioDeviceID
Expand Down Expand Up @@ -243,6 +247,7 @@ class SDL_AudioStream(c_void_p):
SDL_GetNumAudioDevices = _ctypes["SDL_GetNumAudioDevices"]
SDL_GetAudioDeviceName = _ctypes["SDL_GetAudioDeviceName"]
SDL_GetAudioDeviceSpec = _ctypes["SDL_GetAudioDeviceSpec"]
SDL_GetDefaultAudioInfo = _ctypes["SDL_GetDefaultAudioInfo"]
SDL_OpenAudioDevice = _ctypes["SDL_OpenAudioDevice"]
SDL_GetAudioStatus = _ctypes["SDL_GetAudioStatus"]
SDL_GetAudioDeviceStatus = _ctypes["SDL_GetAudioDeviceStatus"]
Expand Down
4 changes: 4 additions & 0 deletions sdl2/gamecontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@
SDL_CONTROLLER_TYPE_PS5 = 7
SDL_CONTROLLER_TYPE_AMAZON_LUNA = 8
SDL_CONTROLLER_TYPE_GOOGLE_STADIA = 9
SDL_CONTROLLER_TYPE_NVIDIA_SHIELD = 10
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT = 11
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT = 12
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR = 13

SDL_GameControllerAxis = c_int
SDL_CONTROLLER_AXIS_INVALID = -1
Expand Down
16 changes: 11 additions & 5 deletions sdl2/guid.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from ctypes import Structure, c_int, c_char, c_char_p
from ctypes import POINTER as _P
import sys
from ctypes import c_int, c_char_p
from .dll import _bind, SDLFunc, AttributeDict
from .stdinc import Uint8
from .joystick import SDL_JoystickGUID

__all__ = [
# Defines
Expand All @@ -11,21 +12,26 @@

# Constants & typedefs

class SDL_GUID(Structure):
_fields_ = [("data", (Uint8 * 16))]
SDL_GUID = SDL_JoystickGUID


# Raw ctypes function definitions

_funcdefs = [
SDLFunc("SDL_GUIDToString", [SDL_GUID, _P(c_char), c_int], None, added='2.23.1'),
SDLFunc("SDL_GUIDToString", [SDL_GUID, c_char_p, c_int], None, added='2.23.1'),
SDLFunc("SDL_GUIDFromString", [c_char_p], SDL_GUID, added='2.23.1'),
]
_ctypes = AttributeDict()
for f in _funcdefs:
_ctypes[f.name] = _bind(f.name, f.args, f.returns, f.added)
__all__.append(f.name) # Add all bound functions to module namespace

# Workaround for bizarre ctypes bug with older Python versions
# (The joystick function here is a thin wrapper around SDL_GUIDToString)
if sys.version_info < (3, 7, 0):
from .joystick import SDL_JoystickGetGUIDString
_ctypes["SDL_GUIDToString"] = SDL_JoystickGetGUIDString


# Aliases for ctypes bindings

Expand Down
14 changes: 14 additions & 0 deletions sdl2/hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@
"SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE",
"SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE",
"SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS",
"SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS",
"SDL_HINT_JOYSTICK_HIDAPI_LUNA",
"SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC",
"SDL_HINT_JOYSTICK_HIDAPI_SHIELD",
"SDL_HINT_JOYSTICK_HIDAPI_PS4",
"SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE",
"SDL_HINT_JOYSTICK_HIDAPI_PS5",
Expand All @@ -58,6 +61,8 @@
"SDL_HINT_JOYSTICK_HIDAPI_STEAM",
"SDL_HINT_JOYSTICK_HIDAPI_SWITCH",
"SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED",
"SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED",
"SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED",
"SDL_HINT_JOYSTICK_HIDAPI_XBOX",
"SDL_HINT_JOYSTICK_RAWINPUT",
"SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT",
Expand All @@ -72,6 +77,7 @@
"SDL_HINT_LINUX_JOYSTICK_DEADZONES",
"SDL_HINT_MAC_BACKGROUND_APP",
"SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK",
"SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH",
"SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS",
"SDL_HINT_MOUSE_DOUBLE_CLICK_TIME",
"SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH",
Expand All @@ -80,6 +86,7 @@
"SDL_HINT_MOUSE_RELATIVE_MODE_WARP",
"SDL_HINT_MOUSE_RELATIVE_SCALING",
"SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE",
"SDL_HINT_MOUSE_RELATIVE_WARP_MOTION",
"SDL_HINT_MOUSE_TOUCH_EVENTS",
"SDL_HINT_MOUSE_AUTO_CAPTURE",
"SDL_HINT_NO_SIGNAL_HANDLERS",
Expand Down Expand Up @@ -257,6 +264,7 @@
SDL_HINT_MOUSE_RELATIVE_MODE_WARP = b"SDL_MOUSE_RELATIVE_MODE_WARP"
SDL_HINT_MOUSE_RELATIVE_SCALING = b"SDL_MOUSE_RELATIVE_SCALING"
SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE = b"SDL_MOUSE_RELATIVE_SPEED_SCALE"
SDL_HINT_MOUSE_RELATIVE_WARP_MOTION = b"SDL_MOUSE_RELATIVE_WARP_MOTION"
SDL_HINT_MOUSE_TOUCH_EVENTS = b"SDL_MOUSE_TOUCH_EVENTS"
SDL_HINT_TOUCH_MOUSE_EVENTS = b"SDL_TOUCH_MOUSE_EVENTS"

Expand All @@ -278,7 +286,10 @@
SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE = b"SDL_JOYSTICK_HIDAPI_GAMECUBE"
SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE = b"SDL_JOYSTICK_GAMECUBE_RUMBLE_BRAKE"
SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS = b"SDL_JOYSTICK_HIDAPI_JOY_CONS"
SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS = b"SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS"
SDL_HINT_JOYSTICK_HIDAPI_LUNA = b"SDL_JOYSTICK_HIDAPI_LUNA"
SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC = b"SDL_JOYSTICK_HIDAPI_NINTENDO_CLASSIC"
SDL_HINT_JOYSTICK_HIDAPI_SHIELD = b"SDL_JOYSTICK_HIDAPI_SHIELD"
SDL_HINT_JOYSTICK_HIDAPI_PS4 = b"SDL_JOYSTICK_HIDAPI_PS4"
SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE = b"SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"
SDL_HINT_JOYSTICK_HIDAPI_PS5 = b"SDL_JOYSTICK_HIDAPI_PS5"
Expand All @@ -288,6 +299,8 @@
SDL_HINT_JOYSTICK_HIDAPI_STEAM = b"SDL_JOYSTICK_HIDAPI_STEAM"
SDL_HINT_JOYSTICK_HIDAPI_SWITCH = b"SDL_JOYSTICK_HIDAPI_SWITCH"
SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED = b"SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED"
SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED = b"SDL_JOYSTICK_HIDAPI_JOYCON_HOME_LED"
SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED = b"SDL_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED"
SDL_HINT_JOYSTICK_HIDAPI_XBOX = b"SDL_JOYSTICK_HIDAPI_XBOX"
SDL_HINT_JOYSTICK_RAWINPUT = b"SDL_JOYSTICK_RAWINPUT"
SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT = b"SDL_JOYSTICK_RAWINPUT_CORRELATE_XINPUT"
Expand All @@ -307,6 +320,7 @@
SDL_HINT_LINUX_JOYSTICK_DEADZONES = b"SDL_LINUX_JOYSTICK_DEADZONES"
SDL_HINT_MAC_BACKGROUND_APP = b"SDL_MAC_BACKGROUND_APP"
SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK = b"SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK"
SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH = b"SDL_MAC_OPENGL_ASYNC_DISPATCH"
SDL_HINT_RPI_VIDEO_LAYER = b"SDL_RPI_VIDEO_LAYER"
SDL_HINT_RENDER_DIRECT3D11_DEBUG = b"SDL_RENDER_DIRECT3D11_DEBUG"
SDL_HINT_RENDER_DIRECT3D_THREADSAFE = b"SDL_RENDER_DIRECT3D_THREADSAFE"
Expand Down
5 changes: 3 additions & 2 deletions sdl2/joystick.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from ctypes import POINTER as _P
from .dll import _bind, SDLFunc, AttributeDict
from .stdinc import Sint16, Sint32, Uint32, Uint16, Uint8, SDL_bool
from .guid import SDL_GUID

__all__ = [
# Structs & Opaque Types
Expand Down Expand Up @@ -72,7 +71,9 @@
# Structs & typedefs

SDL_JoystickID = Sint32
SDL_JoystickGUID = SDL_GUID

class SDL_JoystickGUID(Structure):
_fields_ = [("data", (Uint8 * 16))]

class SDL_Joystick(c_void_p):
pass
Expand Down
2 changes: 2 additions & 0 deletions sdl2/keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class SDL_Keysym(Structure):
_funcdefs = [
SDLFunc("SDL_GetKeyboardFocus", None, _P(SDL_Window)),
SDLFunc("SDL_GetKeyboardState", [_P(c_int)], _P(Uint8)),
SDLFunc("SDL_ResetKeyboard", None, None, added='2.24.0'),
SDLFunc("SDL_GetModState", None, SDL_Keymod),
SDLFunc("SDL_SetModState", [SDL_Keymod]),
SDLFunc("SDL_GetKeyFromScancode", [SDL_Scancode], SDL_Keycode),
Expand Down Expand Up @@ -56,6 +57,7 @@ class SDL_Keysym(Structure):

SDL_GetKeyboardFocus = _ctypes["SDL_GetKeyboardFocus"]
SDL_GetKeyboardState = _ctypes["SDL_GetKeyboardState"]
SDL_ResetKeyboard = _ctypes["SDL_ResetKeyboard"]
SDL_GetModState = _ctypes["SDL_GetModState"]
SDL_SetModState = _ctypes["SDL_SetModState"]
SDL_GetKeyFromScancode = _ctypes["SDL_GetKeyFromScancode"]
Expand Down
66 changes: 49 additions & 17 deletions sdl2/test/audio_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def with_sdl_audio():
if original_driver:
os.environ["SDL_AUDIODRIVER"] = original_driver
# Initialize SDL2 with video and audio subsystems
sdl2.SDL_Quit()
sdl2.SDL_ClearError()
ret = sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO | sdl2.SDL_INIT_AUDIO)
assert sdl2.SDL_GetError() == b""
Expand All @@ -31,6 +32,23 @@ def with_sdl_audio():
if original_driver:
os.environ["SDL_AUDIODRIVER"] = original_driver

@pytest.fixture
def with_default_driver(with_sdl_audio):
driver = sdl2.SDL_GetCurrentAudioDriver()
if driver == None or sdl2.SDL_GetNumAudioDevices(False) == 0:
sdl2.SDL_QuitSubSystem(SDL_INIT_AUDIO)
os.environ["SDL_AUDIODRIVER"] = b'dummy'
sdl2.SDL_InitSubSystem(SDL_INIT_AUDIO)
driver = sdl2.SDL_GetCurrentAudioDriver()
yield driver

def _get_audio_drivers():
drivers = []
for index in range(sdl2.SDL_GetNumAudioDrivers()):
name = sdl2.SDL_GetAudioDriver(index)
drivers.append(name.decode('utf-8'))
return drivers


# Test macro functions

Expand Down Expand Up @@ -227,11 +245,10 @@ def test_SDL_GetAudioDeviceName(with_sdl_audio):
# Reset audio subsystem
SDL_Quit()
SDL_Init(0)
for index in range(sdl2.SDL_GetNumAudioDrivers()):
for drivername in _get_audio_drivers():
# Get input/output device names for each audio driver
drivername = sdl2.SDL_GetAudioDriver(index)
backends.append(drivername.decode("utf-8"))
os.environ["SDL_AUDIODRIVER"] = drivername.decode("utf-8")
backends.append(drivername)
os.environ["SDL_AUDIODRIVER"] = drivername
# Need to reinitialize subsystem for each driver
SDL_InitSubSystem(SDL_INIT_AUDIO)
driver = sdl2.SDL_GetCurrentAudioDriver()
Expand All @@ -258,24 +275,13 @@ def test_SDL_GetAudioDeviceName(with_sdl_audio):
print(" - output: {0}".format(str(devices[driver]['output'])))

@pytest.mark.skipif(sdl2.dll.version < 2016, reason="not available")
def test_SDL_GetAudioDeviceSpec(with_sdl_audio):
# Reset audio subsystem
SDL_Quit()
SDL_Init(0)
# Find an audio driver with at least one output
SDL_InitSubSystem(SDL_INIT_AUDIO)
driver = sdl2.SDL_GetCurrentAudioDriver()
if driver == None or sdl2.SDL_GetNumAudioDevices(False) == 0:
SDL_QuitSubSystem(SDL_INIT_AUDIO)
os.environ["SDL_AUDIODRIVER"] = b'dummy'
SDL_InitSubSystem(SDL_INIT_AUDIO)
driver = sdl2.SDL_GetCurrentAudioDriver()
def test_SDL_GetAudioDeviceSpec(with_default_driver):
driver = with_default_driver
drivername = driver.decode('utf-8')
# Get name and spec of first output device
outspec = sdl2.SDL_AudioSpec(0, 0, 0, 0)
outname = sdl2.SDL_GetAudioDeviceName(0, False).decode('utf-8')
ret = sdl2.SDL_GetAudioDeviceSpec(0, False, ctypes.byref(outspec))
SDL_QuitSubSystem(SDL_INIT_AUDIO)
assert ret == 0
# Validate frequency and channel count were set
hz = outspec.freq
Expand All @@ -291,6 +297,32 @@ def test_SDL_GetAudioDeviceSpec(with_sdl_audio):
print(msg.format(outname, drivername))
print(msg2.format(hz, chans, fmt, bufsize))

@pytest.mark.skipif(sdl2.dll.version < 2240, reason="not available")
def test_SDL_GetDefaultAudioInfo(with_default_driver):
driver = with_default_driver
drivername = driver.decode('utf-8')
# Get name and spec of first output device
outspec = sdl2.SDL_AudioSpec(0, 0, 0, 0)
outname = ctypes.c_char_p()
ret = sdl2.SDL_GetDefaultAudioInfo(ctypes.byref(outname), ctypes.byref(outspec), 0)
# If method isn't implemented for the current back end, just skip
if ret < 0 and b"not supported" in sdl2.SDL_GetError():
pytest.skip("not supported by driver")
assert ret == 0
# Validate frequency and channel count were set
hz = outspec.freq
fmt = FORMAT_NAME_MAP[outspec.format] if outspec.format > 0 else 'unknown'
chans = outspec.channels
bufsize = outspec.samples if outspec.samples > 0 else 'unknown'
assert hz > 0
assert chans > 0
# Print out device spec info
outname = outname.value.decode('utf-8')
msg = "Default audio spec for {0} with '{1}' driver:"
msg2 = "{0} Hz, {1} channels, {2} format, {3} sample buffer size"
print(msg.format(outname, drivername))
print(msg2.format(hz, chans, fmt, bufsize))

def test_SDL_OpenCloseAudioDevice(with_sdl_audio):
#TODO: Add tests for callback
fmt = sdl2.AUDIO_F32 if sys.platform == "darwin" else sdl2.AUDIO_U16
Expand Down
6 changes: 4 additions & 2 deletions sdl2/test/clipboard_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
def window(with_sdl):
flag = sdl2.SDL_WINDOW_BORDERLESS
w = sdl2.SDL_CreateWindow(b"Test", 10, 40, 12, 13, flag)
assert sdl2.SDL_GetError() == b""
assert isinstance(w.contents, sdl2.SDL_Window)
if not isinstance(w.contents, sdl2.SDL_Window):
assert sdl2.SDL_GetError() == b""
assert isinstance(w.contents, sdl2.SDL_Window)
sdl2.SDL_ClearError()
yield w
sdl2.SDL_DestroyWindow(w)

Expand Down
Loading

0 comments on commit ca440b9

Please sign in to comment.