diff --git a/buildconfig/stubs/pygame/mouse.pyi b/buildconfig/stubs/pygame/mouse.pyi index e8e32d6188..c47d60de90 100644 --- a/buildconfig/stubs/pygame/mouse.pyi +++ b/buildconfig/stubs/pygame/mouse.pyi @@ -292,4 +292,6 @@ def set_relative_mode(enable: bool, /) -> None: ``True`` will exit relative mouse mode. .. versionadded:: 2.4.0 + .. versionchanged:: 2.5.6 calling this function before calling + :func:`pygame.display.set_mode` is deprecated and may error in the future. """ diff --git a/src_c/key.c b/src_c/key.c index 2540e59980..9b249c13c7 100644 --- a/src_c/key.c +++ b/src_c/key.c @@ -389,7 +389,11 @@ static const struct { {1073742054, "right alt"}, /* K_RALT */ {1073742055, "right meta"}, /* K_RGUI, K_RMETA, K_RSUPER */ {1073742081, "alt gr"}, /* K_MODE */ - {1073742094, "AC Back"}, /* K_AC_BACK */ +#if SDL_VERSION_ATLEAST(3, 0, 0) + {1073742106, "AC Back"}, /* K_AC_BACK */ +#else + {1073742094, "AC Back"}, /* K_AC_BACK */ +#endif }; /* Get name from keycode using pygame compat table */ diff --git a/src_c/mouse.c b/src_c/mouse.c index 62d1ea6b77..efe71d1b4a 100644 --- a/src_c/mouse.c +++ b/src_c/mouse.c @@ -324,8 +324,9 @@ mouse_get_visible(PyObject *self, PyObject *_null) #if SDL_VERSION_ATLEAST(3, 0, 0) SDL_Window *win = pg_GetDefaultWindow(); - result = - win ? (PG_CursorVisible() && !SDL_GetWindowRelativeMouseMode(win)) : 0; + + /* If win is NULL, SDL_GetWindowRelativeMouseMode returns false */ + result = (PG_CursorVisible() && !SDL_GetWindowRelativeMouseMode(win)); #else result = (PG_CursorVisible() && !SDL_GetRelativeMouseMode()); #endif @@ -618,8 +619,8 @@ mouse_set_relative_mode(PyObject *self, PyObject *arg) if (mode == -1) { return NULL; } -#if SDL_VERSION_ATLEAST(3, 0, 0) SDL_Window *win = pg_GetDefaultWindow(); +#if SDL_VERSION_ATLEAST(3, 0, 0) if (!win) { return RAISE(pgExc_SDLError, "display.set_mode has not been called yet."); @@ -628,6 +629,15 @@ mouse_set_relative_mode(PyObject *self, PyObject *arg) return RAISE(pgExc_SDLError, SDL_GetError()); } #else + if (!win) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "Calling mouse.set_relative_mode before calling " + "display.set_mode has been deprecated and may raise " + "errors in the future.", + 1) == -1) { + return NULL; + } + } if (SDL_SetRelativeMouseMode((SDL_bool)mode)) { return RAISE(pgExc_SDLError, SDL_GetError()); } diff --git a/src_c/pgcompat_rect.c b/src_c/pgcompat_rect.c index 0756da13bc..68548d4bcc 100644 --- a/src_c/pgcompat_rect.c +++ b/src_c/pgcompat_rect.c @@ -1,7 +1,11 @@ #include "pgcompat_rect.h" /* SDL 2.0.22 provides some utility functions for FRects */ -#if !(SDL_VERSION_ATLEAST(2, 0, 22)) +/* SDL3 changed how the edges are handled. Previously right/bottom edges were + * considered excluded from the FRect but now they aren't. + * For now do SDL2 compat, but consider changing this in the future. + * See: https://github.com/pygame-community/pygame-ce/issues/3571 */ +#if !(SDL_VERSION_ATLEAST(2, 0, 22)) || SDL_VERSION_ATLEAST(3, 0, 0) #ifndef CODE_BOTTOM #define CODE_BOTTOM 1 @@ -176,4 +180,4 @@ PG_IntersectFRectAndLine(SDL_FRect *rect, float *X1, float *Y1, float *X2, *Y2 = y2; return SDL_TRUE; } -#endif /* !(SDL_VERSION_ATLEAST(2, 0, 22)) */ +#endif /* !(SDL_VERSION_ATLEAST(2, 0, 22)) || SDL_VERSION_ATLEAST(3, 0, 0) */ diff --git a/src_c/pgcompat_rect.h b/src_c/pgcompat_rect.h index 5bba69dd21..47f7da60ff 100644 --- a/src_c/pgcompat_rect.h +++ b/src_c/pgcompat_rect.h @@ -8,14 +8,14 @@ #endif /* SDL 2.0.22 provides some utility functions for FRects */ -#if !(SDL_VERSION_ATLEAST(2, 0, 22)) +#if !(SDL_VERSION_ATLEAST(2, 0, 22)) || SDL_VERSION_ATLEAST(3, 0, 0) SDL_bool PG_IntersectFRectAndLine(SDL_FRect *rect, float *X1, float *Y1, float *X2, float *Y2); #else #define PG_IntersectFRectAndLine SDL_IntersectFRectAndLine -#endif /* !(SDL_VERSION_ATLEAST(2, 0, 22)) */ +#endif /* !(SDL_VERSION_ATLEAST(2, 0, 22)) || SDL_VERSION_ATLEAST(3, 0, 0) */ #define pg_PyFloat_FromFloat(x) (PyFloat_FromDouble((double)x)) diff --git a/test/key_test.py b/test/key_test.py index 79bd8e1b6f..95176cf57f 100644 --- a/test/key_test.py +++ b/test/key_test.py @@ -8,6 +8,7 @@ # keys that are not tested for const-name match SKIPPED_KEYS = {"K_UNKNOWN"} +SKIPPED_KEYS_NEW = {"K_MODE"} # This is the expected compat output KEY_NAME_COMPAT = { @@ -169,6 +170,7 @@ class KeyModuleTest(unittest.TestCase): @classmethod def setUpClass(cls): + pygame.quit() pygame.init() @classmethod @@ -286,7 +288,8 @@ def test_name_and_key_code(self): # This is a test for an implementation detail of name with use_compat=False # If this test breaks in the future for any key, it is safe to put skips on # failing keys (the implementation detail is documented as being unreliable) - self.assertEqual(pygame.key.key_code(alt_name), const_val) + if const_name not in SKIPPED_KEYS_NEW: + self.assertEqual(pygame.key.key_code(alt_name), const_val) self.assertRaises(TypeError, pygame.key.name, "fizzbuzz") self.assertRaises(TypeError, pygame.key.key_code, pygame.K_a) diff --git a/test/mouse_test.py b/test/mouse_test.py index f7642d6ab6..6a5f2d3df6 100644 --- a/test/mouse_test.py +++ b/test/mouse_test.py @@ -384,6 +384,15 @@ def test_set_visible__invalid_value(self): ) def test_set_relative_mode(self): """Tests that set_relative_mode hides the cursor.""" + for val in (True, False): + if pygame.version.SDL >= (3, 0, 0): + with self.assertRaises(pygame.error): + pygame.mouse.set_relative_mode(val) + else: + with self.assertWarns(DeprecationWarning): + pygame.mouse.set_relative_mode(val) + + pygame.display.set_mode((100, 100)) pygame.mouse.set_visible(True) pygame.mouse.set_relative_mode(True) # sets the mouse invisible visible = pygame.mouse.get_visible() @@ -398,6 +407,7 @@ def test_set_relative_mode(self): ) def test_get_relative_mode(self): """Tests that get_relative_mode correctly reports the relative mode""" + pygame.display.set_mode((100, 100)) pygame.mouse.set_relative_mode(True) self.assertEqual(pygame.mouse.get_relative_mode(), True) pygame.mouse.set_relative_mode(False)