diff --git a/buildconfig/stubs/pygame/display.pyi b/buildconfig/stubs/pygame/display.pyi index f0926fcbaa..43e7f7dff3 100644 --- a/buildconfig/stubs/pygame/display.pyi +++ b/buildconfig/stubs/pygame/display.pyi @@ -39,6 +39,7 @@ def set_mode( depth: int = 0, display: int = 0, vsync: int = 0, + hwnd: int = 0, ) -> Surface: ... def get_surface() -> Surface: ... def flip() -> None: ... diff --git a/docs/reST/ref/display.rst b/docs/reST/ref/display.rst index 740b05a213..c64a83f8a2 100644 --- a/docs/reST/ref/display.rst +++ b/docs/reST/ref/display.rst @@ -113,7 +113,7 @@ required). .. function:: set_mode | :sl:`Initialize a window or screen for display` - | :sg:`set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface` + | :sg:`set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0, hwnd=0) -> Surface` This will create a window or display output and return a display Surface. The arguments passed in are requests for a display type. The actual created @@ -214,6 +214,13 @@ required). .. versionchanged:: 2.2.0 ``vsync=1`` does not require ``SCALED`` or ``OPENGL`` + The ``hwnd`` argument is an integer contains the window id (or handle) of + a foreign window. By setting this parameter, pygame display can be embedded + into the foreign window. Be aware that there can be many strange side effects + when running in an embedded display. + + .. versionadded:: 2.1.4 ``hwnd`` + Basic example: :: diff --git a/src_c/display.c b/src_c/display.c index 2dd3564afc..f75d07e890 100644 --- a/src_c/display.c +++ b/src_c/display.c @@ -839,6 +839,10 @@ pg_set_mode(PyObject *self, PyObject *arg, PyObject *kwds) _DisplayState *state = DISPLAY_MOD_STATE(self); SDL_Window *win = pg_GetDefaultWindow(); +#if !SDL_VERSION_ATLEAST(2, 0, 22) + SDL_Window *dummy = NULL; + char dummy_id_str[64]; +#endif pgSurfaceObject *surface = pg_GetDefaultWindowSurface(); SDL_Surface *surf = NULL; SDL_Surface *newownedsurf = NULL; @@ -858,13 +862,14 @@ pg_set_mode(PyObject *self, PyObject *arg, PyObject *kwds) SDL_VERSION(&wm_info.version); - char *keywords[] = {"size", "flags", "depth", "display", "vsync", NULL}; + char *keywords[] = {"size", "flags", "depth", "display", + "vsync", "hwnd", NULL}; scale_env = SDL_getenv("PYGAME_FORCE_SCALE"); winid_env = SDL_getenv("SDL_WINDOWID"); - if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|Oiiii", keywords, &size, - &flags, &depth, &display, &vsync)) + if (!PyArg_ParseTupleAndKeywords(arg, kwds, "|OiiiiK", keywords, &size, + &flags, &depth, &display, &vsync, &hwnd)) return NULL; if (hwnd == 0 && winid_env != NULL) { @@ -1111,7 +1116,30 @@ pg_set_mode(PyObject *self, PyObject *arg, PyObject *kwds) if (!win) { /*open window*/ if (hwnd != 0) { - win = SDL_CreateWindowFrom((void *)hwnd); + if (flags & PGS_OPENGL) { +#if SDL_VERSION_ATLEAST(2, 0, 22) + SDL_SetHint(SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL, "1"); + win = SDL_CreateWindowFrom((void *)hwnd); + SDL_SetHint(SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL, "0"); +#else + // Create window with SDL_CreateWindowFrom() and OpenGL + // See https://gamedev.stackexchange.com/a/119903 + dummy = SDL_CreateWindow( + "OpenGL Dummy", 0, 0, 1, 1, + SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); + sprintf(dummy_id_str, "%p", dummy); + SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, + dummy_id_str); + + win = SDL_CreateWindowFrom((void *)hwnd); + + SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, + ""); +#endif + } + else { + win = SDL_CreateWindowFrom((void *)hwnd); + } } else { win = SDL_CreateWindow(title, x, y, w_1, h_1, sdl_flags); diff --git a/src_c/doc/display_doc.h b/src_c/doc/display_doc.h index 6f0ae33617..ded1088001 100644 --- a/src_c/doc/display_doc.h +++ b/src_c/doc/display_doc.h @@ -3,7 +3,7 @@ #define DOC_DISPLAY_INIT "init() -> None\nInitialize the display module" #define DOC_DISPLAY_QUIT "quit() -> None\nUninitialize the display module" #define DOC_DISPLAY_GETINIT "get_init() -> bool\nReturns True if the display module has been initialized" -#define DOC_DISPLAY_SETMODE "set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface\nInitialize a window or screen for display" +#define DOC_DISPLAY_SETMODE "set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0, hwnd=0) -> Surface\nInitialize a window or screen for display" #define DOC_DISPLAY_GETSURFACE "get_surface() -> Surface\nGet a reference to the currently set display surface" #define DOC_DISPLAY_FLIP "flip() -> None\nUpdate the full display Surface to the screen" #define DOC_DISPLAY_UPDATE "update(rectangle=None) -> None\nupdate(rectangle_list) -> None\nUpdate portions of the screen for software displays"