From b0c5b6474bac2cea990ef6c6b79ca2730f6c4969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:09:23 +0200 Subject: [PATCH 1/9] Make `PyCursesWindow_Type` a heap type. --- Modules/_cursesmodule.c | 177 +++++++++++++++++++------------ Modules/clinic/_cursesmodule.c.h | 10 +- 2 files changed, 113 insertions(+), 74 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index f13731f6f3660c..e1b5ef16e549b1 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -105,8 +105,9 @@ static const char PyCursesVersion[] = "2.2"; #endif #include "Python.h" -#include "pycore_long.h" // _PyLong_GetZero() -#include "pycore_structseq.h" // _PyStructSequence_NewType() +#include "pycore_capsule.h" // _PyCapsule_SetTraverse() +#include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_structseq.h" // _PyStructSequence_NewType() #ifdef __hpux #define STRICT_SYSV_CURSES @@ -173,6 +174,12 @@ get_cursesmodule_state(PyObject *Py_UNUSED(module)) return &curses_global_state; } +static inline _cursesmodule_state * +get_cursesmodule_state_by_cls(PyTypeObject *Py_UNUSED(cls)) +{ + return &curses_global_state; +} + static inline _cursesmodule_state * get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win)) { @@ -181,9 +188,9 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win)) /*[clinic input] module _curses -class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" +class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=43265c372c2887d6]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/ /* Tells whether setupterm() has been called to initialise terminfo. */ static int curses_setupterm_called = FALSE; @@ -630,10 +637,6 @@ class component_converter(CConverter): The Window Object ******************************************************************************/ -/* Definition of the window type */ - -PyTypeObject PyCursesWindow_Type; - /* Function prototype macros for Window object X - function name @@ -743,10 +746,9 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns") /* Allocation and deallocation of Window Objects */ static PyObject * -PyCursesWindow_New(WINDOW *win, const char *encoding) +PyCursesWindow_New(_cursesmodule_state *state, + WINDOW *win, const char *encoding) { - PyCursesWindowObject *wo; - if (encoding == NULL) { #if defined(MS_WINDOWS) char *buffer[100]; @@ -758,15 +760,19 @@ PyCursesWindow_New(WINDOW *win, const char *encoding) } #elif defined(CODESET) const char *codeset = nl_langinfo(CODESET); - if (codeset != NULL && codeset[0] != 0) + if (codeset != NULL && codeset[0] != 0) { encoding = codeset; + } #endif - if (encoding == NULL) + if (encoding == NULL) { encoding = "utf-8"; + } } - wo = PyObject_New(PyCursesWindowObject, &PyCursesWindow_Type); - if (wo == NULL) return NULL; + PyCursesWindowObject *wo = PyObject_New(PyCursesWindowObject, state->window_type); + if (wo == NULL) { + return NULL; + } wo->win = win; wo->encoding = _PyMem_Strdup(encoding); if (wo->encoding == NULL) { @@ -778,8 +784,10 @@ PyCursesWindow_New(WINDOW *win, const char *encoding) } static void -PyCursesWindow_Dealloc(PyCursesWindowObject *wo) +PyCursesWindow_dealloc(PyObject *self) { + PyTypeObject *window_type = Py_TYPE(self); + PyCursesWindowObject *wo = (PyCursesWindowObject *)self; if (wo->win != stdscr && wo->win != NULL) { // silently ignore errors in delwin(3) (void)delwin(wo->win); @@ -787,7 +795,15 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo) if (wo->encoding != NULL) { PyMem_Free(wo->encoding); } - PyObject_Free(wo); + window_type->tp_free(self); + Py_DECREF(window_type); +} + +static int +PyCursesWindow_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; } /* Addch, Addstr, Addnstr */ @@ -1391,7 +1407,8 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, return NULL; } - return (PyObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + return (PyObject *)PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -2140,7 +2157,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self) /*[clinic input] _curses.window.overlay - destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") + destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type") [ sminrow: int @@ -2169,7 +2186,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, PyCursesWindowObject *destwin, int group_right_1, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol) -/*[clinic end generated code: output=82bb2c4cb443ca58 input=7edd23ad22cc1984]*/ +/*[clinic end generated code: output=82bb2c4cb443ca58 input=6e4b32a7c627a356]*/ { int rtn; @@ -2187,7 +2204,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, /*[clinic input] _curses.window.overwrite - destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type") + destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type") [ sminrow: int @@ -2217,7 +2234,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, int group_right_1, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol) -/*[clinic end generated code: output=12ae007d1681be28 input=ea5de1b35cd948e0]*/ +/*[clinic end generated code: output=12ae007d1681be28 input=d83dd8b24ff2bcc9]*/ { int rtn; @@ -2426,7 +2443,8 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, return NULL; } - return (PyObject *)PyCursesWindow_New(win, self->encoding); + _cursesmodule_state *state = get_cursesmodule_state_by_win(self); + return (PyObject *)PyCursesWindow_New(state, win, self->encoding); } /*[clinic input] @@ -2564,9 +2582,11 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *P return 0; } +#define clinic_state() (get_cursesmodule_state_by_cls(Py_TYPE(self))) #include "clinic/_cursesmodule.c.h" +#undef clinic_state -static PyMethodDef PyCursesWindow_Methods[] = { +static PyMethodDef PyCursesWindow_methods[] = { _CURSES_WINDOW_ADDCH_METHODDEF _CURSES_WINDOW_ADDNSTR_METHODDEF _CURSES_WINDOW_ADDSTR_METHODDEF @@ -2660,42 +2680,26 @@ static PyGetSetDef PyCursesWindow_getsets[] = { {NULL, NULL, NULL, NULL } /* sentinel */ }; -/* -------------------------------------------------------*/ +static PyType_Slot PyCursesWindow_Type_slots[] = { + {Py_tp_methods, PyCursesWindow_methods}, + {Py_tp_getset, PyCursesWindow_getsets}, + {Py_tp_dealloc, PyCursesWindow_dealloc}, + {Py_tp_traverse, PyCursesWindow_traverse}, + {0, NULL} +}; -PyTypeObject PyCursesWindow_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_curses.window", /*tp_name*/ - sizeof(PyCursesWindowObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)PyCursesWindow_Dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - (getattrfunc)0, /*tp_getattr*/ - (setattrfunc)0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - PyCursesWindow_Methods, /*tp_methods*/ - 0, /* tp_members */ - PyCursesWindow_getsets, /* tp_getset */ +static PyType_Spec PyCursesWindow_Type_spec = { + .name = "_curses.window", + .basicsize = sizeof(PyCursesWindowObject), + .flags = Py_TPFLAGS_DEFAULT + | Py_TPFLAGS_DISALLOW_INSTANTIATION + | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_HEAPTYPE, + .slots = PyCursesWindow_Type_slots }; +/* -------------------------------------------------------*/ + /* Function Body Macros - They are ugly but very, very useful. ;-) X - function name @@ -3177,7 +3181,8 @@ _curses_getwin(PyObject *module, PyObject *file) PyErr_SetString(state->error, catchall_NULL); goto error; } - res = PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + res = PyCursesWindow_New(state, win, NULL); error: fclose(fp); @@ -3349,7 +3354,8 @@ _curses_initscr_impl(PyObject *module) if (curses_initscr_called) { wrefresh(stdscr); - return (PyObject *)PyCursesWindow_New(stdscr, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + return (PyObject *)PyCursesWindow_New(state, stdscr, NULL); } win = initscr(); @@ -3452,12 +3458,13 @@ _curses_initscr_impl(PyObject *module) SetDictInt("COLS", COLS); #undef SetDictInt - PyCursesWindowObject *winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + PyObject *winobj = PyCursesWindow_New(state, win, NULL); if (winobj == NULL) { return NULL; } - curses_screen_encoding = winobj->encoding; - return (PyObject *)winobj; + curses_screen_encoding = ((PyCursesWindowObject *)winobj)->encoding; + return winobj; } /*[clinic input] @@ -3829,7 +3836,8 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) return NULL; } - return (PyObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + return (PyObject *)PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -3869,7 +3877,8 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, return NULL; } - return (PyObject *)PyCursesWindow_New(win, NULL); + _cursesmodule_state *state = get_cursesmodule_state(module); + return (PyObject *)PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -4893,11 +4902,40 @@ curses_capi_capsule_destructor(PyObject *op) curses_capi_free(capi); } +static int +curses_capi_capsule_traverse(PyObject *op, visitproc visit, void *arg) +{ + void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME); + assert(capi_ptr != NULL); + Py_VISIT(capi_ptr[0]); // visit curses window type + return 0; +} + +static int +curses_capi_capsule_clear(PyObject *op) +{ + void **capi_ptr = PyCapsule_GetPointer(op, PyCurses_CAPSULE_NAME); + assert(capi_ptr != NULL); + Py_CLEAR(capi_ptr[0]); // clear curses window type + return 0; +} + static PyObject * curses_capi_capsule_new(void *capi) { - return PyCapsule_New(capi, PyCurses_CAPSULE_NAME, - curses_capi_capsule_destructor); + PyObject *capsule = PyCapsule_New(capi, PyCurses_CAPSULE_NAME, + curses_capi_capsule_destructor); + if (capsule == NULL) { + return NULL; + } + if (_PyCapsule_SetTraverse(capsule, + curses_capi_capsule_traverse, + curses_capi_capsule_clear) < 0) + { + Py_DECREF(capsule); + return NULL; + } + return capsule; } /* Module initialization */ @@ -4907,13 +4945,14 @@ cursesmodule_exec(PyObject *module) { _cursesmodule_state *state = get_cursesmodule_state(module); /* Initialize object type */ - if (PyType_Ready(&PyCursesWindow_Type) < 0) { + state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &PyCursesWindow_Type_spec, NULL); + if (state->window_type == NULL) { return -1; } - if (PyModule_AddType(module, &PyCursesWindow_Type) < 0) { + if (PyModule_AddType(module, state->window_type) < 0) { return -1; } - state->window_type = &PyCursesWindow_Type; /* Add some symbolic constants to the module */ PyObject *module_dict = PyModule_GetDict(module); diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 0b52308f10243e..8399c5620f125b 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1389,12 +1389,12 @@ _curses_window_overlay(PyCursesWindowObject *self, PyObject *args) switch (PyTuple_GET_SIZE(args)) { case 1: - if (!PyArg_ParseTuple(args, "O!:overlay", &PyCursesWindow_Type, &destwin)) { + if (!PyArg_ParseTuple(args, "O!:overlay", clinic_state()->window_type, &destwin)) { goto exit; } break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", &PyCursesWindow_Type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { + if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { goto exit; } group_right_1 = 1; @@ -1448,12 +1448,12 @@ _curses_window_overwrite(PyCursesWindowObject *self, PyObject *args) switch (PyTuple_GET_SIZE(args)) { case 1: - if (!PyArg_ParseTuple(args, "O!:overwrite", &PyCursesWindow_Type, &destwin)) { + if (!PyArg_ParseTuple(args, "O!:overwrite", clinic_state()->window_type, &destwin)) { goto exit; } break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", &PyCursesWindow_Type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { + if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { goto exit; } group_right_1 = 1; @@ -4378,4 +4378,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF #define _CURSES_USE_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=8745c1562b537fb4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cd1273354b08948f input=a9049054013a1b77]*/ From cd2c1c569334ec387468f933858ddb072a2d6f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:09:28 +0200 Subject: [PATCH 2/9] update changelog --- Doc/whatsnew/3.14.rst | 5 +++++ .../C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 67d8d389b58082..37faf3fd36ce1c 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -696,6 +696,11 @@ Porting to Python 3.14 implementation details. (Contributed by Victor Stinner in :gh:`120600` and :gh:`124127`.) +* Convert the :ref:`curses.window ` static type exposed + by the :c:macro:`!PyCursesWindow_Type` macro in :file:`Include/py_curses.h` + to a heap type. + (Contributed by Bénédikt Tran in :gh:`123961`.) + Deprecated ---------- diff --git a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst new file mode 100644 index 00000000000000..62457d9b0acfe4 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst @@ -0,0 +1,3 @@ +Convert the :ref:`curses.window ` type exposed by the +:c:macro:`!PyCursesWindow_Type` macro in :file:`Include/py_curses.h` into a +heap type instead of a static type. Patch by Bénédikt Tran. From e46c279fc89d405385c3e47894386748434ee7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:10:41 +0200 Subject: [PATCH 3/9] remove useless casts --- Modules/_cursesmodule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index e1b5ef16e549b1..b43774b840402c 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1408,7 +1408,7 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, } _cursesmodule_state *state = get_cursesmodule_state_by_win(self); - return (PyObject *)PyCursesWindow_New(state, win, NULL); + return PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -2444,7 +2444,7 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, } _cursesmodule_state *state = get_cursesmodule_state_by_win(self); - return (PyObject *)PyCursesWindow_New(state, win, self->encoding); + return PyCursesWindow_New(state, win, self->encoding); } /*[clinic input] @@ -3355,7 +3355,7 @@ _curses_initscr_impl(PyObject *module) if (curses_initscr_called) { wrefresh(stdscr); _cursesmodule_state *state = get_cursesmodule_state(module); - return (PyObject *)PyCursesWindow_New(state, stdscr, NULL); + return PyCursesWindow_New(state, stdscr, NULL); } win = initscr(); @@ -3837,7 +3837,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols) } _cursesmodule_state *state = get_cursesmodule_state(module); - return (PyObject *)PyCursesWindow_New(state, win, NULL); + return PyCursesWindow_New(state, win, NULL); } /*[clinic input] @@ -3878,7 +3878,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols, } _cursesmodule_state *state = get_cursesmodule_state(module); - return (PyObject *)PyCursesWindow_New(state, win, NULL); + return PyCursesWindow_New(state, win, NULL); } /*[clinic input] From 7fcd7790f9673a2c909994078463d651606b88bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:17:15 +0200 Subject: [PATCH 4/9] Keep same formulation for blurb --- .../C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst index 62457d9b0acfe4..a5f590546e85c7 100644 --- a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst +++ b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst @@ -1,3 +1,3 @@ -Convert the :ref:`curses.window ` type exposed by the -:c:macro:`!PyCursesWindow_Type` macro in :file:`Include/py_curses.h` into a -heap type instead of a static type. Patch by Bénédikt Tran. +Convert the :ref:`curses.window ` static type exposed +by the :c:macro:`!PyCursesWindow_Type` macro in :file:`Include/py_curses.h` +to a heap type. Patch by Bénédikt Tran. From ccaf57550de4f86e52dad83646166a9a904d71c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:10:36 +0200 Subject: [PATCH 5/9] Remove What's New entry --- Doc/whatsnew/3.14.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 37faf3fd36ce1c..67d8d389b58082 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -696,11 +696,6 @@ Porting to Python 3.14 implementation details. (Contributed by Victor Stinner in :gh:`120600` and :gh:`124127`.) -* Convert the :ref:`curses.window ` static type exposed - by the :c:macro:`!PyCursesWindow_Type` macro in :file:`Include/py_curses.h` - to a heap type. - (Contributed by Bénédikt Tran in :gh:`123961`.) - Deprecated ---------- From beecc6b235fa2e143fe3d1dcb2db12b768ba2c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:15:11 +0200 Subject: [PATCH 6/9] use Py_TPFLAGS_HAVE_GC --- Modules/_cursesmodule.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index b43774b840402c..5e7d1b237b6090 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -769,7 +769,8 @@ PyCursesWindow_New(_cursesmodule_state *state, } } - PyCursesWindowObject *wo = PyObject_New(PyCursesWindowObject, state->window_type); + PyCursesWindowObject *wo = PyObject_GC_New(PyCursesWindowObject, + state->window_type); if (wo == NULL) { return NULL; } @@ -780,6 +781,7 @@ PyCursesWindow_New(_cursesmodule_state *state, PyErr_NoMemory(); return NULL; } + PyObject_GC_Track((PyObject *)wo); return (PyObject *)wo; } @@ -787,6 +789,7 @@ static void PyCursesWindow_dealloc(PyObject *self) { PyTypeObject *window_type = Py_TYPE(self); + PyObject_GC_Untrack(self); PyCursesWindowObject *wo = (PyCursesWindowObject *)self; if (wo->win != stdscr && wo->win != NULL) { // silently ignore errors in delwin(3) @@ -2694,7 +2697,8 @@ static PyType_Spec PyCursesWindow_Type_spec = { .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_HEAPTYPE, + | Py_TPFLAGS_HEAPTYPE + | Py_TPFLAGS_HAVE_GC, .slots = PyCursesWindow_Type_slots }; From 45183e704622697cc50478c91b3a1b880e413500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:18:05 +0200 Subject: [PATCH 7/9] why am I using GH Web UI --- Modules/_cursesmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 5e7d1b237b6090..0c83fa6899bfa3 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -769,7 +769,7 @@ PyCursesWindow_New(_cursesmodule_state *state, } } - PyCursesWindowObject *wo = PyObject_GC_New(PyCursesWindowObject, + PyCursesWindowObject *wo = PyObject_GC_New(PyCursesWindowObject, state->window_type); if (wo == NULL) { return NULL; From 9c787bcab91fd8c26f10282aec46cd6c6a70e1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:20:35 +0200 Subject: [PATCH 8/9] ... --- Modules/_cursesmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 0c83fa6899bfa3..61b65675375547 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -789,7 +789,7 @@ static void PyCursesWindow_dealloc(PyObject *self) { PyTypeObject *window_type = Py_TYPE(self); - PyObject_GC_Untrack(self); + PyObject_GC_UnTrack(self); PyCursesWindowObject *wo = (PyCursesWindowObject *)self; if (wo->win != stdscr && wo->win != NULL) { // silently ignore errors in delwin(3) From f5485e94b50a488b3ae307b00e231a00244ad4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:08:25 +0200 Subject: [PATCH 9/9] Update 2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst We also remove the use of a the `file` role since we incorrectly used it :') --- .../next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst index a5f590546e85c7..40c26e15a2de92 100644 --- a/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst +++ b/Misc/NEWS.d/next/C_API/2024-10-03-14-06-08.gh-issue-123961.uwJQTY.rst @@ -1,3 +1,3 @@ Convert the :ref:`curses.window ` static type exposed -by the :c:macro:`!PyCursesWindow_Type` macro in :file:`Include/py_curses.h` -to a heap type. Patch by Bénédikt Tran. +by the :c:macro:`!PyCursesWindow_Type` macro in ``Include/py_curses.h`` to a +:ref:`heap type `. Patch by Bénédikt Tran.