Skip to content

Add Window.handle #3219

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion buildconfig/stubs/pygame/window.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Tuple, Union
from typing import Optional, Tuple, Dict, Union
from typing_extensions import deprecated # added in 3.13

from pygame.typing import Point, RectLike
Expand Down Expand Up @@ -70,6 +70,8 @@ class Window:
def position(self, value: Union[int, Point]) -> None: ...
@property
def opengl(self) -> bool: ...
@property
def wm_info(self) -> Dict[str, int]: ...
@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")
def from_display_module(cls) -> Window: ...
12 changes: 12 additions & 0 deletions docs/reST/ref/window.rst
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,18 @@

.. versionadded:: 2.5.0

.. attribute:: wm_info

| :sl:`Get information about the current windowing system`
| :sg:`wm_info -> dict`

Creates a dictionary filled with string keys. The strings and values are
arbitrarily created by the system. Some systems may have no information and
an empty dictionary will be returned. Most platforms will return a "window"
key with the value set to the system id for the window.

.. versionaddedold:: 2.5.3

.. classmethod:: from_display_module

| :sl:`Create a Window object using window data from display module`
Expand Down
1 change: 1 addition & 0 deletions src_c/doc/window_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_WMINFO "wm_info -> dict\nGet information about the current windowing system"
#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"
#define DOC_WINDOW_FLIP "flip() -> None\nUpdate the display surface to the window."
Expand Down
116 changes: 116 additions & 0 deletions src_c/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "doc/sdl2_video_doc.h"
#include "doc/window_doc.h"

#include <SDL_syswm.h>

static int is_window_mod_init = 0;

#if !defined(__APPLE__)
Expand Down Expand Up @@ -779,6 +781,119 @@ window_get_opengl(pgWindowObject *self, void *v)
return PyBool_FromLong(hasGL);
}

static PyObject *
window_get_wm_info(pgWindowObject *self, void *v)
{
PyObject *dict;
PyObject *tmp;
SDL_SysWMinfo info;

SDL_VERSION(&(info.version))
dict = PyDict_New();
if (!dict)
return NULL;

SDL_Window *win = self->_win;
if (!SDL_GetWindowWMInfo(win, &info))
return dict;

(void)tmp;
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
tmp = PyLong_FromLongLong((long long)info.info.win.window);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);

tmp = PyLong_FromLongLong((long long)info.info.win.hdc);
PyDict_SetItemString(dict, "hdc", tmp);
Py_DECREF(tmp);
tmp = PyLong_FromLongLong((long long)info.info.win.hinstance);
PyDict_SetItemString(dict, "hinstance", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_WINRT)
tmp = PyCapsule_New(info.info.winrt.window, "window", NULL);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_X11)
tmp = PyLong_FromLong(info.info.x11.window);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);

tmp = PyCapsule_New(info.info.x11.display, "display", NULL);
PyDict_SetItemString(dict, "display", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_DIRECTFB)
tmp = PyCapsule_New(info.info.dfb.dfb, "dfb", NULL);
PyDict_SetItemString(dict, "dfb", tmp);
Py_DECREF(tmp);

tmp = PyCapsule_New(info.info.dfb.window, "window", NULL);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);

tmp = PyCapsule_New(info.info.dfb.surface, "surface", NULL);
PyDict_SetItemString(dict, "surface", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_COCOA)
tmp = PyCapsule_New(info.info.cocoa.window, "window", NULL);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_UIKIT)
tmp = PyCapsule_New(info.info.uikit.window, "window", NULL);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);

tmp = PyLong_FromLong(info.info.uikit.framebuffer);
PyDict_SetItemString(dict, "framebuffer", tmp);
Py_DECREF(tmp);

tmp = PyLong_FromLong(info.info.uikit.colorbuffer);
PyDict_SetItemString(dict, "colorbuffer", tmp);
Py_DECREF(tmp);

tmp = PyLong_FromLong(info.info.uikit.resolveFramebuffer);
PyDict_SetItemString(dict, "resolveFramebuffer", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_WAYLAND)
tmp = PyCapsule_New(info.info.wl.display, "display", NULL);
PyDict_SetItemString(dict, "display", tmp);
Py_DECREF(tmp);

tmp = PyCapsule_New(info.info.wl.surface, "surface", NULL);
PyDict_SetItemString(dict, "surface", tmp);
Py_DECREF(tmp);

tmp = PyCapsule_New(info.info.wl.shell_surface, "shell_surface", NULL);
PyDict_SetItemString(dict, "shell_surface", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_ANDROID)
tmp = PyCapsule_New(info.info.android.window, "window", NULL);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);

tmp = PyLong_FromLong((long)info.info.android.surface);
PyDict_SetItemString(dict, "surface", tmp);
Py_DECREF(tmp);
#endif
#if defined(SDL_VIDEO_DRIVER_VIVANTE)
tmp = PyLong_FromLong((long)info.info.vivante.display);
PyDict_SetItemString(dict, "display", tmp);
Py_DECREF(tmp);

tmp = PyLong_FromLong((long)info.info.vivante.window);
PyDict_SetItemString(dict, "window", tmp);
Py_DECREF(tmp);
#endif

return dict;
}

static void
window_dealloc(pgWindowObject *self, PyObject *_null)
{
Expand Down Expand Up @@ -1195,6 +1310,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},
{"wm_info", (getter)window_get_wm_info, NULL, DOC_WINDOW_WMINFO, NULL},
{NULL, 0, NULL, NULL, NULL} /* Sentinel */
};

Expand Down
35 changes: 35 additions & 0 deletions test/window_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,41 @@ def test_window_focused(self):
window = pygame.Window()
self.assertIsInstance(window.focused, bool)

def test_wm_info(self):
window = pygame.Window()
wm_info = window.wm_info
self.assertIsInstance(wm_info, dict)

wm_info_potential_keys = {
"colorbuffer",
"connection",
"data",
"dfb",
"display",
"framebuffer",
"fswindow",
"hdc",
"hglrc",
"hinstance",
"lock_func",
"resolveFramebuffer",
"shell_surface",
"surface",
"taskHandle",
"unlock_func",
"wimpVersion",
"window",
"wmwindow",
}

# If any unexpected dict keys are present, they
# will be stored in set wm_info_remaining_keys
wm_info_remaining_keys = set(wm_info.keys()).difference(wm_info_potential_keys)

# Assert set is empty (& therefore does not
# contain unexpected dict keys)
self.assertFalse(wm_info_remaining_keys)

def tearDown(self):
self.win.destroy()

Expand Down
Loading