diff --git a/Include/py_curses.h b/Include/py_curses.h index e11bfedb17d205..49fc3c9d127aa6 100644 --- a/Include/py_curses.h +++ b/Include/py_curses.h @@ -75,10 +75,11 @@ extern "C" { /* Type declarations */ -typedef struct { +typedef struct PyCursesWindowObject { PyObject_HEAD WINDOW *win; char *encoding; + struct PyCursesWindowObject *orig; } PyCursesWindowObject; #define PyCurses_CAPSULE_NAME "_curses._C_API" diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index cc3aa561cd4c42..116112f9feb6bc 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -8,7 +8,8 @@ from unittest.mock import MagicMock from test.support import (requires, verbose, SaveSignals, cpython_only, - check_disallow_instantiation, MISSING_C_DOCSTRINGS) + check_disallow_instantiation, MISSING_C_DOCSTRINGS, + gc_collect) from test.support.import_helper import import_module # Optionally test curses module. This currently requires that the @@ -181,6 +182,14 @@ def test_create_windows(self): self.assertEqual(win3.getparyx(), (2, 1)) self.assertEqual(win3.getmaxyx(), (6, 11)) + def test_subwindows_references(self): + win = curses.newwin(5, 10) + win2 = win.subwin(3, 7) + del win + gc_collect() + del win2 + gc_collect() + def test_move_cursor(self): stdscr = self.stdscr win = stdscr.subwin(10, 15, 2, 5) diff --git a/Misc/NEWS.d/next/Library/2021-05-18-19-12-58.bpo-44172.rJ_-CI.rst b/Misc/NEWS.d/next/Library/2021-05-18-19-12-58.bpo-44172.rJ_-CI.rst new file mode 100644 index 00000000000000..d53f3725100eb2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-05-18-19-12-58.bpo-44172.rJ_-CI.rst @@ -0,0 +1,2 @@ +Keep a reference to original :mod:`curses` windows in subwindows so +that the original window does not get deleted before subwindows. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index bf18cb51605075..6da3ab0fe251f1 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -787,7 +787,8 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns") static PyObject * PyCursesWindow_New(cursesmodule_state *state, - WINDOW *win, const char *encoding) + WINDOW *win, const char *encoding, + PyCursesWindowObject *orig) { if (encoding == NULL) { #if defined(MS_WINDOWS) @@ -821,6 +822,8 @@ PyCursesWindow_New(cursesmodule_state *state, PyErr_NoMemory(); return NULL; } + wo->orig = orig; + Py_XINCREF(orig); PyObject_GC_Track((PyObject *)wo); return (PyObject *)wo; } @@ -838,6 +841,7 @@ PyCursesWindow_dealloc(PyObject *self) if (wo->encoding != NULL) { PyMem_Free(wo->encoding); } + Py_XDECREF(wo->orig); window_type->tp_free(self); Py_DECREF(window_type); } @@ -846,6 +850,8 @@ static int PyCursesWindow_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); + PyCursesWindowObject *wo = (PyCursesWindowObject *)self; + Py_VISIT(wo->orig); return 0; } @@ -1453,7 +1459,7 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, } cursesmodule_state *state = get_cursesmodule_state_by_win(self); - return PyCursesWindow_New(state, win, NULL); + return PyCursesWindow_New(state, win, NULL, self); } /*[clinic input] @@ -2493,7 +2499,7 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, } cursesmodule_state *state = get_cursesmodule_state_by_win(self); - return PyCursesWindow_New(state, win, self->encoding); + return PyCursesWindow_New(state, win, self->encoding, self); } /*[clinic input] @@ -3237,7 +3243,7 @@ _curses_getwin(PyObject *module, PyObject *file) goto error; } cursesmodule_state *state = get_cursesmodule_state(module); - res = PyCursesWindow_New(state, win, NULL); + res = PyCursesWindow_New(state, win, NULL, NULL); error: fclose(fp); @@ -3410,7 +3416,7 @@ _curses_initscr_impl(PyObject *module) if (curses_initscr_called) { wrefresh(stdscr); cursesmodule_state *state = get_cursesmodule_state(module); - return PyCursesWindow_New(state, stdscr, NULL); + return PyCursesWindow_New(state, stdscr, NULL, NULL); } win = initscr(); @@ -3514,7 +3520,7 @@ _curses_initscr_impl(PyObject *module) #undef SetDictInt cursesmodule_state *state = get_cursesmodule_state(module); - PyObject *winobj = PyCursesWindow_New(state, win, NULL); + PyObject *winobj = PyCursesWindow_New(state, win, NULL, NULL); if (winobj == NULL) { return NULL; } @@ -3898,7 +3904,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) } cursesmodule_state *state = get_cursesmodule_state(module); - return PyCursesWindow_New(state, win, NULL); + return PyCursesWindow_New(state, win, NULL, NULL); } /*[clinic input] @@ -3939,7 +3945,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, } cursesmodule_state *state = get_cursesmodule_state(module); - return PyCursesWindow_New(state, win, NULL); + return PyCursesWindow_New(state, win, NULL, NULL); } /*[clinic input] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy