diff --git a/src_c/_sdl2/controller.c b/src_c/_sdl2/controller.c index 648af64a09..cba8927d5e 100644 --- a/src_c/_sdl2/controller.c +++ b/src_c/_sdl2/controller.c @@ -26,11 +26,19 @@ static PyObject * controller_module_init(PyObject *module, PyObject *_null) { if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (!SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)) { +#else if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)) { +#endif return RAISE(pgExc_SDLError, SDL_GetError()); } } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SetGamepadEventsEnabled(SDL_TRUE); +#else SDL_GameControllerEventState(SDL_ENABLE); +#endif Py_RETURN_NONE; } @@ -87,7 +95,16 @@ controller_module_get_count(PyObject *module, PyObject *_null) { CONTROLLER_INIT_CHECK(); +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count; + SDL_JoystickID *joysticks = SDL_GetJoysticks(&count); + if (!joysticks) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + SDL_free(joysticks); +#else int count = SDL_NumJoysticks(); +#endif if (count < 0) { return RAISE(pgExc_SDLError, SDL_GetError()); } @@ -290,7 +307,11 @@ controller_set_mapping(pgControllerObject *self, PyObject *args, char guid_str[64]; SDL_Joystick *joy = SDL_GameControllerGetJoystick(self->controller); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_GUIDToString(SDL_JoystickGetGUID(joy), guid_str, 63); +#else SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), guid_str, 63); +#endif PyObject *key, *value; const char *key_str, *value_str; @@ -371,10 +392,17 @@ controller_rumble(pgControllerObject *self, PyObject *args, PyObject *kwargs) low_freq = MAX(MIN(low_freq, 1.0f), 0.0f) * 65535; high_freq = MAX(MIN(high_freq, 1.0f), 0.0f) * 65535; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_bool success = SDL_GameControllerRumble( + self->controller, (Uint16)low_freq, (Uint16)high_freq, duration); + + return PyBool_FromLong(success); +#else int success = SDL_GameControllerRumble(self->controller, (Uint16)low_freq, (Uint16)high_freq, duration); - return PyBool_FromLong(success == 0); + +#endif } static PyObject * @@ -384,7 +412,9 @@ controller_stop_rumble(pgControllerObject *self, PyObject *_null) if (!self->controller) { return RAISE(pgExc_SDLError, "Controller is not initialized"); } - SDL_GameControllerRumble(self->controller, 0, 0, 1); + if (!SDL_GameControllerRumble(self->controller, 0, 0, 1)) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } Py_RETURN_NONE; } @@ -437,7 +467,18 @@ controller_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) CONTROLLER_INIT_CHECK(); - if (id >= SDL_NumJoysticks() || !SDL_IsGameController(id)) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + int joycount; + SDL_JoystickID *joysticks = SDL_GetJoysticks(&joycount); + if (!joysticks) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + SDL_free(joysticks); +#else + int joycount = SDL_NumJoysticks(); +#endif + + if (id >= joycount || !SDL_IsGameController(id)) { return RAISE(pgExc_SDLError, "Invalid index"); } diff --git a/src_c/_sdl2/meson.build b/src_c/_sdl2/meson.build index 2ad443e993..5b6ff36893 100644 --- a/src_c/_sdl2/meson.build +++ b/src_c/_sdl2/meson.build @@ -1,5 +1,6 @@ cython_base = '../cython/pygame/_sdl2' +if sdl_api != 3 _sdl2_audio = py.extension_module( 'audio', fs.is_file('audio.c') ? 'audio.c' : cython_base / 'audio.pyx', @@ -37,6 +38,7 @@ if sdl_mixer_dep.found() subdir: pg / '_sdl2', ) endif +endif _sdl2_sdl2 = py.extension_module( 'sdl2', @@ -47,7 +49,7 @@ _sdl2_sdl2 = py.extension_module( subdir: pg / '_sdl2', ) -# This is not a cython file +# These are not cython files _sdl2_touch = py.extension_module( 'touch', 'touch.c', diff --git a/src_c/_sdl2/touch.c b/src_c/_sdl2/touch.c index 1c7bd83b57..c432d0555f 100644 --- a/src_c/_sdl2/touch.c +++ b/src_c/_sdl2/touch.c @@ -25,20 +25,48 @@ static PyObject * pg_touch_num_devices(PyObject *self, PyObject *_null) { - return PyLong_FromLong(SDL_GetNumTouchDevices()); + int count; +#if SDL_VERSION_ATLEAST(3, 0, 0) + + SDL_TouchID *devices = SDL_GetTouchDevices(&count); + if (devices == NULL) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + SDL_free(devices); +#else + count = SDL_GetNumTouchDevices(); +#endif + return PyLong_FromLong(count); } static PyObject * -pg_touch_get_device(PyObject *self, PyObject *index) +pg_touch_get_device(PyObject *self, PyObject *index_obj) { SDL_TouchID touchid; - if (!PyLong_Check(index)) { + if (!PyLong_Check(index_obj)) { return RAISE(PyExc_TypeError, "index must be an integer " "specifying a device to get the ID for"); } - - touchid = SDL_GetTouchDevice(PyLong_AsLong(index)); + int index = PyLong_AsLong(index_obj); + if (PyErr_Occurred()) { + return NULL; // exception already set + } +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count; + SDL_TouchID *devices = SDL_GetTouchDevices(&count); + if (devices == NULL) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + if (index < 0 || index >= count) { + SDL_free(devices); + return RAISE(PyExc_IndexError, "index is out of bounds"); + } + touchid = devices[index]; + SDL_free(devices); +#else + touchid = SDL_GetTouchDevice(index); +#endif if (touchid == 0) { /* invalid index */ return RAISE(pgExc_SDLError, SDL_GetError()); @@ -47,21 +75,32 @@ pg_touch_get_device(PyObject *self, PyObject *index) } static PyObject * -pg_touch_num_fingers(PyObject *self, PyObject *device_id) +pg_touch_num_fingers(PyObject *self, PyObject *device_id_obj) { int fingercount; - if (!PyLong_Check(device_id)) { + if (!PyLong_Check(device_id_obj)) { return RAISE(PyExc_TypeError, "device_id must be an integer " "specifying a touch device"); } + int device_id = PyLong_AsLongLong(device_id_obj); + if (PyErr_Occurred()) { + return NULL; // exception already set + } VIDEO_INIT_CHECK(); - - fingercount = SDL_GetNumTouchFingers(PyLong_AsLongLong(device_id)); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Finger **fingers = SDL_GetTouchFingers(device_id, &fingercount); + if (fingers == NULL) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + SDL_free(fingers); +#else + fingercount = SDL_GetNumTouchFingers(device_id); if (fingercount == 0) { return RAISE(pgExc_SDLError, SDL_GetError()); } +#endif return PyLong_FromLong(fingercount); } #if !defined(BUILD_STATIC) @@ -95,14 +134,28 @@ pg_touch_get_finger(PyObject *self, PyObject *args, PyObject *kwargs) } VIDEO_INIT_CHECK(); - +#if SDL_VERSION_ATLEAST(3, 0, 0) + int fingercount; + SDL_Finger **fingers = SDL_GetTouchFingers(touchid, &fingercount); + if (fingers == NULL) { + return RAISE(pgExc_SDLError, SDL_GetError()); + } + if (index < 0 || index >= fingercount) { + SDL_free(fingers); + return RAISE(PyExc_IndexError, "index is out of bounds"); + } + finger = fingers[index]; + SDL_free(fingers); +#else if (!(finger = SDL_GetTouchFinger(touchid, index))) { Py_RETURN_NONE; } +#endif fingerobj = PyDict_New(); - if (!fingerobj) + if (!fingerobj) { return NULL; + } _pg_insobj(fingerobj, "id", PyLong_FromLongLong(finger->id)); _pg_insobj(fingerobj, "x", PyFloat_FromDouble(finger->x)); diff --git a/src_c/cython/pygame/_sdl2/sdl2.pxd b/src_c/cython/pygame/_sdl2/sdl2.pxd index a7cca25180..2281787ba8 100644 --- a/src_c/cython/pygame/_sdl2/sdl2.pxd +++ b/src_c/cython/pygame/_sdl2/sdl2.pxd @@ -4,7 +4,17 @@ from libc.string cimport memset from libc.stdio cimport * -cdef extern from "SDL.h" nogil: +cdef extern from * nogil: + """ + #ifdef PG_SDL3 + #include + #define SDL_INIT_TIMER 0 + #define SDL_INIT_EVERYTHING 0 + #define SDL_INIT_NOPARACHUTE 0 + #else + #include + #endif + """ # SDL_stdinc.h provides the real ones based on platform. ctypedef char Sint8 ctypedef unsigned char Uint8 diff --git a/src_c/meson.build b/src_c/meson.build index 0c1479a812..377fdf517a 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -327,10 +327,7 @@ gfxdraw = py.extension_module( endif # pygame._sdl2 -# TODO: support SDL3 -if sdl_api != 3 subdir('_sdl2') -endif # pygame._camera pg_camera_sources = ['_camera.c'] diff --git a/src_py/_sdl2/__init__.py b/src_py/_sdl2/__init__.py index 6ad3b1b047..c29a5342a6 100644 --- a/src_py/_sdl2/__init__.py +++ b/src_py/_sdl2/__init__.py @@ -1,4 +1,9 @@ +from pygame.version import SDL + if __import__("sys").platform not in ("wasi", "emscripten"): - from .audio import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] + if SDL < (3, 0, 0): + from .audio import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] from .sdl2 import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] - from .video import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] + + if SDL < (3, 0, 0): + from .video import * # pylint: disable=wildcard-import; lgtm[py/polluting-import]