@@ -32,6 +32,8 @@ typedef struct {
32
32
PyTypeObject * PyCursesPanel_Type ;
33
33
} _curses_panel_state ;
34
34
35
+ typedef struct PyCursesPanelObject PyCursesPanelObject ;
36
+
35
37
static inline _curses_panel_state *
36
38
get_curses_panel_state (PyObject * module )
37
39
{
@@ -40,6 +42,25 @@ get_curses_panel_state(PyObject *module)
40
42
return (_curses_panel_state * )state ;
41
43
}
42
44
45
+ static inline _curses_panel_state *
46
+ get_curses_panel_state_by_panel (PyCursesPanelObject * panel )
47
+ {
48
+ /*
49
+ * Note: 'state' may be NULL if Py_TYPE(panel) is not a heap
50
+ * type associated with this module, but the compiler would
51
+ * have likely already complained with an "invalid pointer
52
+ * type" at compile-time.
53
+ *
54
+ * To make it more robust, all functions recovering a module's
55
+ * state from an object should expect to return NULL with an
56
+ * exception set (in contrast to functions recovering a module's
57
+ * state from a module itself).
58
+ */
59
+ void * state = PyType_GetModuleState (Py_TYPE (panel ));
60
+ assert (state != NULL );
61
+ return (_curses_panel_state * )state ;
62
+ }
63
+
43
64
static int
44
65
_curses_panel_clear (PyObject * mod )
45
66
{
@@ -95,7 +116,7 @@ PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname)
95
116
96
117
/* Definition of the panel object and panel type */
97
118
98
- typedef struct {
119
+ typedef struct PyCursesPanelObject {
99
120
PyObject_HEAD
100
121
PANEL * pan ;
101
122
PyCursesWindowObject * wo ; /* for reference counts */
@@ -262,8 +283,11 @@ static PyObject *
262
283
PyCursesPanel_New (_curses_panel_state * state , PANEL * pan ,
263
284
PyCursesWindowObject * wo )
264
285
{
265
- PyCursesPanelObject * po = PyObject_New (PyCursesPanelObject ,
266
- state -> PyCursesPanel_Type );
286
+ assert (state != NULL );
287
+ PyTypeObject * type = state -> PyCursesPanel_Type ;
288
+ assert (type != NULL );
289
+ assert (type -> tp_alloc != NULL );
290
+ PyCursesPanelObject * po = (PyCursesPanelObject * )type -> tp_alloc (type , 0 );
267
291
if (po == NULL ) {
268
292
return NULL ;
269
293
}
@@ -278,27 +302,57 @@ PyCursesPanel_New(_curses_panel_state *state, PANEL *pan,
278
302
return (PyObject * )po ;
279
303
}
280
304
305
+ static int
306
+ PyCursesPanel_Clear (PyObject * op )
307
+ {
308
+ PyCursesPanelObject * self = _PyCursesPanelObject_CAST (op );
309
+ PyObject * extra = (PyObject * )panel_userptr (self -> pan );
310
+ if (extra != NULL ) {
311
+ Py_DECREF (extra );
312
+ if (set_panel_userptr (self -> pan , NULL ) == ERR ) {
313
+ _curses_panel_state * state = get_curses_panel_state_by_panel (self );
314
+ PyErr_SetString (state -> PyCursesError ,
315
+ "set_panel_userptr() returned ERR" );
316
+ return -1 ;
317
+ }
318
+ }
319
+ // self->wo should not be cleared because an associated WINDOW may exist
320
+ return 0 ;
321
+ }
322
+
281
323
static void
282
324
PyCursesPanel_Dealloc (PyObject * self )
283
325
{
284
- PyObject * tp , * obj ;
285
- PyCursesPanelObject * po = _PyCursesPanelObject_CAST (self );
326
+ PyTypeObject * tp = Py_TYPE ( self ) ;
327
+ PyObject_GC_UnTrack (self );
286
328
287
- tp = (PyObject * ) Py_TYPE (po );
288
- obj = (PyObject * ) panel_userptr (po -> pan );
289
- if (obj ) {
290
- (void )set_panel_userptr (po -> pan , NULL );
291
- Py_DECREF (obj );
329
+ PyCursesPanelObject * po = _PyCursesPanelObject_CAST (self );
330
+ if (PyCursesPanel_Clear (self ) < 0 ) {
331
+ PyErr_FormatUnraisable ("Exception ignored in PyCursesPanel_Dealloc()" );
332
+ }
333
+ if (del_panel (po -> pan ) == ERR && !PyErr_Occurred ()) {
334
+ _curses_panel_state * state = get_curses_panel_state_by_panel (po );
335
+ PyErr_SetString (state -> PyCursesError , "del_panel() returned ERR" );
336
+ PyErr_FormatUnraisable ("Exception ignored in PyCursesPanel_Dealloc()" );
292
337
}
293
- (void )del_panel (po -> pan );
294
338
if (po -> wo != NULL ) {
295
339
Py_DECREF (po -> wo );
296
340
remove_lop (po );
297
341
}
298
- PyObject_Free (po );
342
+ tp -> tp_free (po );
299
343
Py_DECREF (tp );
300
344
}
301
345
346
+ static int
347
+ PyCursesPanel_Traverse (PyObject * op , visitproc visit , void * arg )
348
+ {
349
+ PyCursesPanelObject * self = _PyCursesPanelObject_CAST (op );
350
+ Py_VISIT (Py_TYPE (op ));
351
+ Py_VISIT (panel_userptr (self -> pan ));
352
+ Py_VISIT (self -> wo );
353
+ return 0 ;
354
+ }
355
+
302
356
/* panel_above(NULL) returns the bottom panel in the stack. To get
303
357
this behaviour we use curses.panel.bottom_panel(). */
304
358
/*[clinic input]
@@ -520,15 +574,21 @@ static PyMethodDef PyCursesPanel_Methods[] = {
520
574
/* -------------------------------------------------------*/
521
575
522
576
static PyType_Slot PyCursesPanel_Type_slots [] = {
577
+ {Py_tp_clear , PyCursesPanel_Clear },
523
578
{Py_tp_dealloc , PyCursesPanel_Dealloc },
579
+ {Py_tp_traverse , PyCursesPanel_Traverse },
524
580
{Py_tp_methods , PyCursesPanel_Methods },
525
581
{0 , 0 },
526
582
};
527
583
528
584
static PyType_Spec PyCursesPanel_Type_spec = {
529
585
.name = "_curses_panel.panel" ,
530
586
.basicsize = sizeof (PyCursesPanelObject ),
531
- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION ,
587
+ .flags = (
588
+ Py_TPFLAGS_DEFAULT
589
+ | Py_TPFLAGS_DISALLOW_INSTANTIATION
590
+ | Py_TPFLAGS_HAVE_GC
591
+ ),
532
592
.slots = PyCursesPanel_Type_slots
533
593
};
534
594
0 commit comments