@@ -410,8 +410,11 @@ static PyObject *
410410PyCursesPanel_New (_curses_panel_state * state , PANEL * pan ,
411411 PyCursesWindowObject * wo )
412412{
413- PyCursesPanelObject * po = PyObject_New (PyCursesPanelObject ,
414- state -> PyCursesPanel_Type );
413+ assert (state != NULL );
414+ PyTypeObject * type = state -> PyCursesPanel_Type ;
415+ assert (type != NULL );
416+ assert (type -> tp_alloc != NULL );
417+ PyCursesPanelObject * po = (PyCursesPanelObject * )type -> tp_alloc (type , 0 );
415418 if (po == NULL ) {
416419 return NULL ;
417420 }
@@ -426,20 +429,31 @@ PyCursesPanel_New(_curses_panel_state *state, PANEL *pan,
426429 return (PyObject * )po ;
427430}
428431
432+ static int
433+ PyCursesPanel_Clear (PyObject * op )
434+ {
435+ PyCursesPanelObject * self = _PyCursesPanelObject_CAST (op );
436+ PyObject * extra = (PyObject * )panel_userptr (self -> pan );
437+ if (extra != NULL ) {
438+ Py_DECREF (extra );
439+ if (set_panel_userptr (self -> pan , NULL ) == ERR ) {
440+ curses_panel_panel_set_error (self , "set_panel_userptr" , NULL );
441+ return -1 ;
442+ }
443+ }
444+ // self->wo should not be cleared because an associated WINDOW may exist
445+ return 0 ;
446+ }
447+
429448static void
430449PyCursesPanel_Dealloc (PyObject * self )
431450{
432- PyObject * tp , * obj ;
433- PyCursesPanelObject * po = _PyCursesPanelObject_CAST (self );
451+ PyTypeObject * tp = Py_TYPE ( self ) ;
452+ PyObject_GC_UnTrack (self );
434453
435- tp = (PyObject * ) Py_TYPE (po );
436- obj = (PyObject * ) panel_userptr (po -> pan );
437- if (obj ) {
438- Py_DECREF (obj );
439- if (set_panel_userptr (po -> pan , NULL ) == ERR ) {
440- curses_panel_panel_set_error (po , "set_panel_userptr" , "__del__" );
441- PyErr_FormatUnraisable ("Exception ignored in PyCursesPanel_Dealloc()" );
442- }
454+ PyCursesPanelObject * po = _PyCursesPanelObject_CAST (self );
455+ if (PyCursesPanel_Clear (self ) < 0 ) {
456+ PyErr_FormatUnraisable ("Exception ignored in PyCursesPanel_Dealloc()" );
443457 }
444458 if (del_panel (po -> pan ) == ERR && !PyErr_Occurred ()) {
445459 curses_panel_panel_set_error (po , "del_panel" , "__del__" );
@@ -452,10 +466,20 @@ PyCursesPanel_Dealloc(PyObject *self)
452466 PyErr_FormatUnraisable ("Exception ignored in PyCursesPanel_Dealloc()" );
453467 }
454468 }
455- PyObject_Free (po );
469+ tp -> tp_free (po );
456470 Py_DECREF (tp );
457471}
458472
473+ static int
474+ PyCursesPanel_Traverse (PyObject * op , visitproc visit , void * arg )
475+ {
476+ PyCursesPanelObject * self = _PyCursesPanelObject_CAST (op );
477+ Py_VISIT (Py_TYPE (op ));
478+ Py_VISIT (panel_userptr (self -> pan ));
479+ Py_VISIT (self -> wo );
480+ return 0 ;
481+ }
482+
459483/* panel_above(NULL) returns the bottom panel in the stack. To get
460484 this behaviour we use curses.panel.bottom_panel(). */
461485/*[clinic input]
@@ -647,15 +671,21 @@ static PyMethodDef PyCursesPanel_Methods[] = {
647671/* -------------------------------------------------------*/
648672
649673static PyType_Slot PyCursesPanel_Type_slots [] = {
674+ {Py_tp_clear , PyCursesPanel_Clear },
650675 {Py_tp_dealloc , PyCursesPanel_Dealloc },
676+ {Py_tp_traverse , PyCursesPanel_Traverse },
651677 {Py_tp_methods , PyCursesPanel_Methods },
652678 {0 , 0 },
653679};
654680
655681static PyType_Spec PyCursesPanel_Type_spec = {
656682 .name = "_curses_panel.panel" ,
657683 .basicsize = sizeof (PyCursesPanelObject ),
658- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION ,
684+ .flags = (
685+ Py_TPFLAGS_DEFAULT
686+ | Py_TPFLAGS_DISALLOW_INSTANTIATION
687+ | Py_TPFLAGS_HAVE_GC
688+ ),
659689 .slots = PyCursesPanel_Type_slots
660690};
661691
0 commit comments