diff --git a/buildconfig/stubs/pygame/window.pyi b/buildconfig/stubs/pygame/window.pyi index ac948b4931..8bcd04bdaa 100644 --- a/buildconfig/stubs/pygame/window.pyi +++ b/buildconfig/stubs/pygame/window.pyi @@ -71,6 +71,8 @@ class Window: @property def opengl(self) -> bool: ... @property + def handle(self) -> int: ... + @property def utility(self) -> bool: ... @classmethod @deprecated("since 2.4.0. Use either the display module or the Window class with get_surface and flip. Try not to mix display and Window") diff --git a/docs/reST/ref/window.rst b/docs/reST/ref/window.rst index b460047bd7..e64a8803d4 100644 --- a/docs/reST/ref/window.rst +++ b/docs/reST/ref/window.rst @@ -289,6 +289,19 @@ .. versionadded:: 2.5.0 + .. attribute:: handle + + | :sl:`Get the window handle provided by the window manager if supported otherwise 0` + | :sg:`handle -> int` + + Returns the window handle provided by the window manager as an integer. If the operating + system is not supported or the window manager hides the handle the sentinel ``0`` is returned. + + The handle is generally available with Windows, X11 (Linux), Cocoa (MacOS), UIKit (iOS), + Android and Vivante while unavailable under Wayland and everything else. + + .. versionaddedold:: 2.5.3 + .. attribute:: utility | :sl:`Get if the window is an utility window (**read-only**)` diff --git a/src_c/doc/window_doc.h b/src_c/doc/window_doc.h index 8a1063a54b..d4f65f1a49 100644 --- a/src_c/doc/window_doc.h +++ b/src_c/doc/window_doc.h @@ -17,6 +17,7 @@ #define DOC_WINDOW_POSITION "position -> (int, int) or WINDOWPOS_CENTERED or WINDOWPOS_UNDEFINED\nGet or set the window position in screen coordinates" #define DOC_WINDOW_OPACITY "opacity -> float\nGet or set the window opacity, between 0.0 (fully transparent) and 1.0 (fully opaque)" #define DOC_WINDOW_OPENGL "opengl -> bool\nGet if the window supports OpenGL" +#define DOC_WINDOW_HANDLE "handle -> int\nGet the window handle provided by the window manager if supported otherwise 0" #define DOC_WINDOW_UTILITY "utility -> bool\nGet if the window is an utility window (**read-only**)" #define DOC_WINDOW_FROMDISPLAYMODULE "from_display_module() -> Window\nCreate a Window object using window data from display module" #define DOC_WINDOW_GETSURFACE "get_surface() -> Surface\nGet the window surface" diff --git a/src_c/window.c b/src_c/window.c index 8934898d4d..f98016fa02 100644 --- a/src_c/window.c +++ b/src_c/window.c @@ -8,6 +8,10 @@ #include "doc/sdl2_video_doc.h" #include "doc/window_doc.h" +#if !SDL_VERSION_ATLEAST(3, 0, 0) +#include +#endif + static int is_window_mod_init = 0; #if !defined(__APPLE__) @@ -785,6 +789,75 @@ window_get_opengl(pgWindowObject *self, void *v) return PyBool_FromLong(hasGL); } +static PyObject * +window_get_handle(pgWindowObject *self, void *v) +{ + SDL_Window *win = self->_win; + size_t handle = 0; + +#if SDL_VERSION_ATLEAST(3, 1, 3) + SDL_PropertiesID props = SDL_GetWindowProperties(window); + +#if defined(SDL_VIDEO_DRIVER_WINDOWS) + handle = (size_t)SDL_GetPointerProperty( + props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); +#endif +#if defined(SDL_VIDEO_DRIVER_X11) + handle = (size_t)SDL_GetNumberProperty( + props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, NULL); +#endif +#if defined(SDL_VIDEO_DRIVER_COCOA) + handle = (size_t)SDL_GetPointerProperty( + props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); +#endif +#if defined(SDL_VIDEO_DRIVER_UIKIT) + handle = (size_t)SDL_GetPointerProperty( + props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, NULL); +#endif +// wayland does not support window handle +#if defined(SDL_VIDEO_DRIVER_ANDROID) + handle = (size_t)SDL_GetPointerProperty( + props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, NULL); +#endif +#if defined(SDL_VIDEO_DRIVER_VIVANTE) + handle = (size_t)SDL_GetPointerProperty( + props, SDL_PROP_WINDOW_VIVANTE_WINDOW_POINTER, NULL); +#endif + +#else // sdl 2 + SDL_SysWMinfo info; + + SDL_VERSION(&(info.version)) + + if (!SDL_GetWindowWMInfo(win, &info)) + return PyLong_FromLong(0); + +#if defined(SDL_VIDEO_DRIVER_WINDOWS) + handle = (size_t)info.info.win.window; +#endif +// WINRT window handle not supported in SDL3 +#if defined(SDL_VIDEO_DRIVER_X11) + handle = (size_t)info.info.x11.window; +#endif +// DIRECTFB wm info not supported in SDL3 +#if defined(SDL_VIDEO_DRIVER_COCOA) + handle = (size_t)info.info.cocoa.window; +#endif +#if defined(SDL_VIDEO_DRIVER_UIKIT) + handle = (size_t)info.info.uikit.window; +#endif +// wayland does not support window handle +#if defined(SDL_VIDEO_DRIVER_ANDROID) + handle = (size_t)info.info.android.window; +#endif +#if defined(SDL_VIDEO_DRIVER_VIVANTE) + handle = (size_t)info.info.vivante.window; +#endif +#endif // sdl 3 + + return PyLong_FromSize_t(handle); +} + static PyObject * window_get_utility(pgWindowObject *self, void *v) { @@ -1222,6 +1295,7 @@ static PyGetSetDef _window_getset[] = { DOC_WINDOW_OPACITY, NULL}, {"id", (getter)window_get_window_id, NULL, DOC_WINDOW_ID, NULL}, {"opengl", (getter)window_get_opengl, NULL, DOC_WINDOW_OPENGL, NULL}, + {"handle", (getter)window_get_handle, NULL, DOC_WINDOW_HANDLE, NULL}, {"utility", (getter)window_get_utility, NULL, DOC_WINDOW_UTILITY, NULL}, {NULL, 0, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/test/window_test.py b/test/window_test.py index f30ab08bc5..4d044a867c 100644 --- a/test/window_test.py +++ b/test/window_test.py @@ -458,6 +458,10 @@ def test_window_focused(self): window = pygame.Window() self.assertIsInstance(window.focused, bool) + def test_handle(self): + window = pygame.Window() + self.assertIsInstance(window.handle, int) + def tearDown(self): self.win.destroy()