@@ -105,8 +105,9 @@ static const char PyCursesVersion[] = "2.2";
105105#endif
106106
107107#include "Python.h"
108- #include "pycore_long.h" // _PyLong_GetZero()
109- #include "pycore_structseq.h" // _PyStructSequence_NewType()
108+ #include "pycore_capsule.h" // _PyCapsule_SetTraverse()
109+ #include "pycore_long.h" // _PyLong_GetZero()
110+ #include "pycore_structseq.h" // _PyStructSequence_NewType()
110111
111112#ifdef __hpux
112113#define STRICT_SYSV_CURSES
@@ -173,6 +174,12 @@ get_cursesmodule_state(PyObject *Py_UNUSED(module))
173174 return & curses_global_state ;
174175}
175176
177+ static inline _cursesmodule_state *
178+ get_cursesmodule_state_by_cls (PyTypeObject * Py_UNUSED (cls ))
179+ {
180+ return & curses_global_state ;
181+ }
182+
176183static inline _cursesmodule_state *
177184get_cursesmodule_state_by_win (PyCursesWindowObject * Py_UNUSED (win ))
178185{
@@ -181,9 +188,9 @@ get_cursesmodule_state_by_win(PyCursesWindowObject *Py_UNUSED(win))
181188
182189/*[clinic input]
183190module _curses
184- class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type "
191+ class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type "
185192[clinic start generated code]*/
186- /*[clinic end generated code: output=da39a3ee5e6b4b0d input=43265c372c2887d6 ]*/
193+ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc ]*/
187194
188195/* Tells whether setupterm() has been called to initialise terminfo. */
189196static int curses_setupterm_called = FALSE;
@@ -630,10 +637,6 @@ class component_converter(CConverter):
630637 The Window Object
631638******************************************************************************/
632639
633- /* Definition of the window type */
634-
635- PyTypeObject PyCursesWindow_Type ;
636-
637640/* Function prototype macros for Window object
638641
639642 X - function name
@@ -743,10 +746,9 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
743746/* Allocation and deallocation of Window Objects */
744747
745748static PyObject *
746- PyCursesWindow_New (WINDOW * win , const char * encoding )
749+ PyCursesWindow_New (_cursesmodule_state * state ,
750+ WINDOW * win , const char * encoding )
747751{
748- PyCursesWindowObject * wo ;
749-
750752 if (encoding == NULL ) {
751753#if defined(MS_WINDOWS )
752754 char * buffer [100 ];
@@ -758,36 +760,53 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
758760 }
759761#elif defined(CODESET )
760762 const char * codeset = nl_langinfo (CODESET );
761- if (codeset != NULL && codeset [0 ] != 0 )
763+ if (codeset != NULL && codeset [0 ] != 0 ) {
762764 encoding = codeset ;
765+ }
763766#endif
764- if (encoding == NULL )
767+ if (encoding == NULL ) {
765768 encoding = "utf-8" ;
769+ }
766770 }
767771
768- wo = PyObject_New (PyCursesWindowObject , & PyCursesWindow_Type );
769- if (wo == NULL ) return NULL ;
772+ PyCursesWindowObject * wo = PyObject_GC_New (PyCursesWindowObject ,
773+ state -> window_type );
774+ if (wo == NULL ) {
775+ return NULL ;
776+ }
770777 wo -> win = win ;
771778 wo -> encoding = _PyMem_Strdup (encoding );
772779 if (wo -> encoding == NULL ) {
773780 Py_DECREF (wo );
774781 PyErr_NoMemory ();
775782 return NULL ;
776783 }
784+ PyObject_GC_Track ((PyObject * )wo );
777785 return (PyObject * )wo ;
778786}
779787
780788static void
781- PyCursesWindow_Dealloc ( PyCursesWindowObject * wo )
789+ PyCursesWindow_dealloc ( PyObject * self )
782790{
791+ PyTypeObject * window_type = Py_TYPE (self );
792+ PyObject_GC_UnTrack (self );
793+ PyCursesWindowObject * wo = (PyCursesWindowObject * )self ;
783794 if (wo -> win != stdscr && wo -> win != NULL ) {
784795 // silently ignore errors in delwin(3)
785796 (void )delwin (wo -> win );
786797 }
787798 if (wo -> encoding != NULL ) {
788799 PyMem_Free (wo -> encoding );
789800 }
790- PyObject_Free (wo );
801+ window_type -> tp_free (self );
802+ Py_DECREF (window_type );
803+ }
804+
805+ static int
806+ PyCursesWindow_traverse (PyObject * self , visitproc visit , void * arg )
807+ {
808+ Py_VISIT (Py_TYPE (self ));
809+ return 0 ;
791810}
792811
793812/* Addch, Addstr, Addnstr */
@@ -1391,7 +1410,8 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
13911410 return NULL ;
13921411 }
13931412
1394- return (PyObject * )PyCursesWindow_New (win , NULL );
1413+ _cursesmodule_state * state = get_cursesmodule_state_by_win (self );
1414+ return PyCursesWindow_New (state , win , NULL );
13951415}
13961416
13971417/*[clinic input]
@@ -2140,7 +2160,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self)
21402160/*[clinic input]
21412161_curses.window.overlay
21422162
2143- destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type ")
2163+ destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type ")
21442164
21452165 [
21462166 sminrow: int
@@ -2169,7 +2189,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self,
21692189 PyCursesWindowObject * destwin , int group_right_1 ,
21702190 int sminrow , int smincol , int dminrow ,
21712191 int dmincol , int dmaxrow , int dmaxcol )
2172- /*[clinic end generated code: output=82bb2c4cb443ca58 input=7edd23ad22cc1984 ]*/
2192+ /*[clinic end generated code: output=82bb2c4cb443ca58 input=6e4b32a7c627a356 ]*/
21732193{
21742194 int rtn ;
21752195
@@ -2187,7 +2207,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self,
21872207/*[clinic input]
21882208_curses.window.overwrite
21892209
2190- destwin: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type ")
2210+ destwin: object(type="PyCursesWindowObject *", subclass_of="clinic_state()->window_type ")
21912211
21922212 [
21932213 sminrow: int
@@ -2217,7 +2237,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self,
22172237 int group_right_1 , int sminrow , int smincol ,
22182238 int dminrow , int dmincol , int dmaxrow ,
22192239 int dmaxcol )
2220- /*[clinic end generated code: output=12ae007d1681be28 input=ea5de1b35cd948e0 ]*/
2240+ /*[clinic end generated code: output=12ae007d1681be28 input=d83dd8b24ff2bcc9 ]*/
22212241{
22222242 int rtn ;
22232243
@@ -2426,7 +2446,8 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1,
24262446 return NULL ;
24272447 }
24282448
2429- return (PyObject * )PyCursesWindow_New (win , self -> encoding );
2449+ _cursesmodule_state * state = get_cursesmodule_state_by_win (self );
2450+ return PyCursesWindow_New (state , win , self -> encoding );
24302451}
24312452
24322453/*[clinic input]
@@ -2564,9 +2585,11 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *P
25642585 return 0 ;
25652586}
25662587
2588+ #define clinic_state () (get_cursesmodule_state_by_cls(Py_TYPE(self)))
25672589#include "clinic/_cursesmodule.c.h"
2590+ #undef clinic_state
25682591
2569- static PyMethodDef PyCursesWindow_Methods [] = {
2592+ static PyMethodDef PyCursesWindow_methods [] = {
25702593 _CURSES_WINDOW_ADDCH_METHODDEF
25712594 _CURSES_WINDOW_ADDNSTR_METHODDEF
25722595 _CURSES_WINDOW_ADDSTR_METHODDEF
@@ -2660,42 +2683,27 @@ static PyGetSetDef PyCursesWindow_getsets[] = {
26602683 {NULL , NULL , NULL , NULL } /* sentinel */
26612684};
26622685
2663- /* -------------------------------------------------------*/
2686+ static PyType_Slot PyCursesWindow_Type_slots [] = {
2687+ {Py_tp_methods , PyCursesWindow_methods },
2688+ {Py_tp_getset , PyCursesWindow_getsets },
2689+ {Py_tp_dealloc , PyCursesWindow_dealloc },
2690+ {Py_tp_traverse , PyCursesWindow_traverse },
2691+ {0 , NULL }
2692+ };
26642693
2665- PyTypeObject PyCursesWindow_Type = {
2666- PyVarObject_HEAD_INIT (NULL , 0 )
2667- "_curses.window" , /*tp_name*/
2668- sizeof (PyCursesWindowObject ), /*tp_basicsize*/
2669- 0 , /*tp_itemsize*/
2670- /* methods */
2671- (destructor )PyCursesWindow_Dealloc , /*tp_dealloc*/
2672- 0 , /*tp_vectorcall_offset*/
2673- (getattrfunc )0 , /*tp_getattr*/
2674- (setattrfunc )0 , /*tp_setattr*/
2675- 0 , /*tp_as_async*/
2676- 0 , /*tp_repr*/
2677- 0 , /*tp_as_number*/
2678- 0 , /*tp_as_sequence*/
2679- 0 , /*tp_as_mapping*/
2680- 0 , /*tp_hash*/
2681- 0 , /*tp_call*/
2682- 0 , /*tp_str*/
2683- 0 , /*tp_getattro*/
2684- 0 , /*tp_setattro*/
2685- 0 , /*tp_as_buffer*/
2686- Py_TPFLAGS_DEFAULT , /*tp_flags*/
2687- 0 , /*tp_doc*/
2688- 0 , /*tp_traverse*/
2689- 0 , /*tp_clear*/
2690- 0 , /*tp_richcompare*/
2691- 0 , /*tp_weaklistoffset*/
2692- 0 , /*tp_iter*/
2693- 0 , /*tp_iternext*/
2694- PyCursesWindow_Methods , /*tp_methods*/
2695- 0 , /* tp_members */
2696- PyCursesWindow_getsets , /* tp_getset */
2694+ static PyType_Spec PyCursesWindow_Type_spec = {
2695+ .name = "_curses.window" ,
2696+ .basicsize = sizeof (PyCursesWindowObject ),
2697+ .flags = Py_TPFLAGS_DEFAULT
2698+ | Py_TPFLAGS_DISALLOW_INSTANTIATION
2699+ | Py_TPFLAGS_IMMUTABLETYPE
2700+ | Py_TPFLAGS_HEAPTYPE
2701+ | Py_TPFLAGS_HAVE_GC ,
2702+ .slots = PyCursesWindow_Type_slots
26972703};
26982704
2705+ /* -------------------------------------------------------*/
2706+
26992707/* Function Body Macros - They are ugly but very, very useful. ;-)
27002708
27012709 X - function name
@@ -3177,7 +3185,8 @@ _curses_getwin(PyObject *module, PyObject *file)
31773185 PyErr_SetString (state -> error , catchall_NULL );
31783186 goto error ;
31793187 }
3180- res = PyCursesWindow_New (win , NULL );
3188+ _cursesmodule_state * state = get_cursesmodule_state (module );
3189+ res = PyCursesWindow_New (state , win , NULL );
31813190
31823191error :
31833192 fclose (fp );
@@ -3349,7 +3358,8 @@ _curses_initscr_impl(PyObject *module)
33493358
33503359 if (curses_initscr_called ) {
33513360 wrefresh (stdscr );
3352- return (PyObject * )PyCursesWindow_New (stdscr , NULL );
3361+ _cursesmodule_state * state = get_cursesmodule_state (module );
3362+ return PyCursesWindow_New (state , stdscr , NULL );
33533363 }
33543364
33553365 win = initscr ();
@@ -3452,12 +3462,13 @@ _curses_initscr_impl(PyObject *module)
34523462 SetDictInt ("COLS" , COLS );
34533463#undef SetDictInt
34543464
3455- PyCursesWindowObject * winobj = (PyCursesWindowObject * )PyCursesWindow_New (win , NULL );
3465+ _cursesmodule_state * state = get_cursesmodule_state (module );
3466+ PyObject * winobj = PyCursesWindow_New (state , win , NULL );
34563467 if (winobj == NULL ) {
34573468 return NULL ;
34583469 }
3459- curses_screen_encoding = winobj -> encoding ;
3460- return ( PyObject * ) winobj ;
3470+ curses_screen_encoding = (( PyCursesWindowObject * ) winobj ) -> encoding ;
3471+ return winobj ;
34613472}
34623473
34633474/*[clinic input]
@@ -3829,7 +3840,8 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols)
38293840 return NULL ;
38303841 }
38313842
3832- return (PyObject * )PyCursesWindow_New (win , NULL );
3843+ _cursesmodule_state * state = get_cursesmodule_state (module );
3844+ return PyCursesWindow_New (state , win , NULL );
38333845}
38343846
38353847/*[clinic input]
@@ -3869,7 +3881,8 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols,
38693881 return NULL ;
38703882 }
38713883
3872- return (PyObject * )PyCursesWindow_New (win , NULL );
3884+ _cursesmodule_state * state = get_cursesmodule_state (module );
3885+ return PyCursesWindow_New (state , win , NULL );
38733886}
38743887
38753888/*[clinic input]
@@ -4893,11 +4906,40 @@ curses_capi_capsule_destructor(PyObject *op)
48934906 curses_capi_free (capi );
48944907}
48954908
4909+ static int
4910+ curses_capi_capsule_traverse (PyObject * op , visitproc visit , void * arg )
4911+ {
4912+ void * * capi_ptr = PyCapsule_GetPointer (op , PyCurses_CAPSULE_NAME );
4913+ assert (capi_ptr != NULL );
4914+ Py_VISIT (capi_ptr [0 ]); // visit curses window type
4915+ return 0 ;
4916+ }
4917+
4918+ static int
4919+ curses_capi_capsule_clear (PyObject * op )
4920+ {
4921+ void * * capi_ptr = PyCapsule_GetPointer (op , PyCurses_CAPSULE_NAME );
4922+ assert (capi_ptr != NULL );
4923+ Py_CLEAR (capi_ptr [0 ]); // clear curses window type
4924+ return 0 ;
4925+ }
4926+
48964927static PyObject *
48974928curses_capi_capsule_new (void * capi )
48984929{
4899- return PyCapsule_New (capi , PyCurses_CAPSULE_NAME ,
4900- curses_capi_capsule_destructor );
4930+ PyObject * capsule = PyCapsule_New (capi , PyCurses_CAPSULE_NAME ,
4931+ curses_capi_capsule_destructor );
4932+ if (capsule == NULL ) {
4933+ return NULL ;
4934+ }
4935+ if (_PyCapsule_SetTraverse (capsule ,
4936+ curses_capi_capsule_traverse ,
4937+ curses_capi_capsule_clear ) < 0 )
4938+ {
4939+ Py_DECREF (capsule );
4940+ return NULL ;
4941+ }
4942+ return capsule ;
49014943}
49024944
49034945/* Module initialization */
@@ -4907,13 +4949,14 @@ cursesmodule_exec(PyObject *module)
49074949{
49084950 _cursesmodule_state * state = get_cursesmodule_state (module );
49094951 /* Initialize object type */
4910- if (PyType_Ready (& PyCursesWindow_Type ) < 0 ) {
4952+ state -> window_type = (PyTypeObject * )PyType_FromModuleAndSpec (
4953+ module , & PyCursesWindow_Type_spec , NULL );
4954+ if (state -> window_type == NULL ) {
49114955 return -1 ;
49124956 }
4913- if (PyModule_AddType (module , & PyCursesWindow_Type ) < 0 ) {
4957+ if (PyModule_AddType (module , state -> window_type ) < 0 ) {
49144958 return -1 ;
49154959 }
4916- state -> window_type = & PyCursesWindow_Type ;
49174960
49184961 /* Add some symbolic constants to the module */
49194962 PyObject * module_dict = PyModule_GetDict (module );
0 commit comments