diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index d87374a298fc337..bf0b5c4b885a277 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -3056,6 +3056,33 @@ def test_window_keeps_screen_alive(self): win.addstr(0, 0, 'still alive') win.refresh() + @unittest.skipUnless(hasattr(curses.screen, 'use'), + 'requires curses.screen.use()') + def test_window_made_in_use_keeps_its_screen_alive(self): + # use() makes its screen current for the callback, so a window created + # there belongs to that screen and must keep it alive, not the screen + # that was current before. + s = self.make_pty() + s2 = self.make_pty() + a = curses.newterm('xterm', s, s) + b = curses.newterm('xterm', s2, s2) # current screen is b + win = a.use(lambda scr: curses.newwin(3, 3)) + del a + gc_collect() + win.addstr(0, 0, 'x') + b.stdscr.refresh() + + @unittest.skipUnless(hasattr(curses.screen, 'use'), + 'requires curses.screen.use()') + def test_initscr_in_use_returns_its_screen(self): + # initscr() returns the standard window of the current screen, and + # inside use() that is the used screen. + s = self.make_pty() + s2 = self.make_pty() + a = curses.newterm('xterm', s, s) + b = curses.newterm('xterm', s2, s2) # current screen is b + self.assertIs(a.use(lambda scr: curses.initscr()), a.stdscr) + def test_screen_freed(self): # Dropping all references to a (non-current) screen and its windows # frees it without error. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 383de378670ea97..006e27d55d8925d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -5303,8 +5303,8 @@ static PyObject * PyCursesScreen_use(PyObject *self, PyObject *args, PyObject *kwargs) { PyCursesScreenObject *so = _PyCursesScreenObject_CAST(self); + cursesmodule_state *state = get_cursesmodule_state_by_cls(Py_TYPE(self)); if (so->screen == NULL) { - cursesmodule_state *state = get_cursesmodule_state_by_cls(Py_TYPE(self)); PyErr_SetString(state->error, "the screen has been deleted"); return NULL; } @@ -5313,7 +5313,10 @@ PyCursesScreen_use(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; } curses_use_data data = {self, func, extra, kwargs, NULL}; + PyObject *prev = state->topscreen; + state->topscreen = Py_NewRef(self); use_screen(so->screen, curses_use_screen_cb, &data); + Py_SETREF(state->topscreen, prev); Py_DECREF(extra); return data.result; }