#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
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))
{
/*[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;
The Window Object
******************************************************************************/
-/* Definition of the window type */
-
-PyTypeObject PyCursesWindow_Type;
-
/* Function prototype macros for Window object
X - function name
/* 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];
}
#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_GC_New(PyCursesWindowObject,
+ state->window_type);
+ if (wo == NULL) {
+ return NULL;
+ }
wo->win = win;
wo->encoding = _PyMem_Strdup(encoding);
if (wo->encoding == NULL) {
PyErr_NoMemory();
return NULL;
}
+ PyObject_GC_Track((PyObject *)wo);
return (PyObject *)wo;
}
static void
-PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
+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)
(void)delwin(wo->win);
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 */
return NULL;
}
- return (PyObject *)PyCursesWindow_New(win, NULL);
+ _cursesmodule_state *state = get_cursesmodule_state_by_win(self);
+ return PyCursesWindow_New(state, win, NULL);
}
/*[clinic input]
/*[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
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;
/*[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
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;
return NULL;
}
- return (PyObject *)PyCursesWindow_New(win, self->encoding);
+ _cursesmodule_state *state = get_cursesmodule_state_by_win(self);
+ return PyCursesWindow_New(state, win, self->encoding);
}
/*[clinic input]
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
{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
+ | Py_TPFLAGS_HAVE_GC,
+ .slots = PyCursesWindow_Type_slots
};
+/* -------------------------------------------------------*/
+
/* Function Body Macros - They are ugly but very, very useful. ;-)
X - function name
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);
if (curses_initscr_called) {
wrefresh(stdscr);
- return (PyObject *)PyCursesWindow_New(stdscr, NULL);
+ _cursesmodule_state *state = get_cursesmodule_state(module);
+ return PyCursesWindow_New(state, stdscr, NULL);
}
win = initscr();
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]
return NULL;
}
- return (PyObject *)PyCursesWindow_New(win, NULL);
+ _cursesmodule_state *state = get_cursesmodule_state(module);
+ return PyCursesWindow_New(state, win, NULL);
}
/*[clinic input]
return NULL;
}
- return (PyObject *)PyCursesWindow_New(win, NULL);
+ _cursesmodule_state *state = get_cursesmodule_state(module);
+ return PyCursesWindow_New(state, win, NULL);
}
/*[clinic input]
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 */
{
_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);