blob: a98d2bf3f85f5488827055c35f84e078ef3c2cdd [file] [log] [blame]
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +00001/*
2 * Interface to the ncurses panel library
3 *
4 * Original version by Thomas Gellekum
5 */
6
7/* Release Number */
8
Serhiy Storchaka2d06e842015-12-25 19:53:18 +02009static const char PyCursesVersion[] = "2.1";
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000010
11/* Includes */
12
13#include "Python.h"
14
15#include "py_curses.h"
16
17#include <panel.h>
18
Martin v. Löwisc838ec12012-06-14 16:00:24 +020019typedef struct {
20 PyObject *PyCursesError;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +020021 PyObject *PyCursesPanel_Type;
Martin v. Löwisc838ec12012-06-14 16:00:24 +020022} _curses_panelstate;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000023
Martin v. Löwisc838ec12012-06-14 16:00:24 +020024#define _curses_panelstate(o) ((_curses_panelstate *)PyModule_GetState(o))
25
Martin v. Löwisc838ec12012-06-14 16:00:24 +020026static int
27_curses_panel_clear(PyObject *m)
28{
29 Py_CLEAR(_curses_panelstate(m)->PyCursesError);
30 return 0;
31}
32
33static int
34_curses_panel_traverse(PyObject *m, visitproc visit, void *arg)
35{
36 Py_VISIT(_curses_panelstate(m)->PyCursesError);
37 return 0;
38}
39
40static void
41_curses_panel_free(void *m)
42{
43 _curses_panel_clear((PyObject *) m);
44}
45
46static struct PyModuleDef _curses_panelmodule;
47
48#define _curses_panelstate_global \
49((_curses_panelstate *) PyModule_GetState(PyState_FindModule(&_curses_panelmodule)))
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000050
51/* Utility Functions */
52
53/*
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000054 * Check the return code from a curses function and return None
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000055 * or raise an exception as appropriate.
56 */
57
58static PyObject *
Serhiy Storchakaef1585e2015-12-25 20:01:53 +020059PyCursesCheckERR(int code, const char *fname)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000060{
61 if (code != ERR) {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +020062 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000063 } else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 if (fname == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +020065 PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_ERR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000066 } else {
Martin v. Löwisc838ec12012-06-14 16:00:24 +020067 PyErr_Format(_curses_panelstate_global->PyCursesError, "%s() returned ERR", fname);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 }
69 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000070 }
71}
72
73/*****************************************************************************
74 The Panel Object
75******************************************************************************/
76
77/* Definition of the panel object and panel type */
78
79typedef struct {
80 PyObject_HEAD
81 PANEL *pan;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 PyCursesWindowObject *wo; /* for reference counts */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000083} PyCursesPanelObject;
84
Martin v. Löwisbc07cb82012-06-14 16:01:23 +020085#define PyCursesPanel_Check(v) \
86 (Py_TYPE(v) == _curses_panelstate_global->PyCursesPanel_Type)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000087
88/* Some helper functions. The problem is that there's always a window
89 associated with a panel. To ensure that Python's GC doesn't pull
90 this window from under our feet we need to keep track of references
91 to the corresponding window object within Python. We can't use
92 dupwin(oldwin) to keep a copy of the curses WINDOW because the
93 contents of oldwin is copied only once; code like
94
95 win = newwin(...)
96 pan = win.panel()
97 win.addstr(some_string)
98 pan.window().addstr(other_string)
99
100 will fail. */
101
102/* We keep a linked list of PyCursesPanelObjects, lop. A list should
103 suffice, I don't expect more than a handful or at most a few
104 dozens of panel objects within a typical program. */
105typedef struct _list_of_panels {
106 PyCursesPanelObject *po;
107 struct _list_of_panels *next;
108} list_of_panels;
109
110/* list anchor */
111static list_of_panels *lop;
112
113/* Insert a new panel object into lop */
114static int
115insert_lop(PyCursesPanelObject *po)
116{
117 list_of_panels *new;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000118
Victor Stinnerb6404912013-07-07 16:21:41 +0200119 if ((new = (list_of_panels *)PyMem_Malloc(sizeof(list_of_panels))) == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000120 PyErr_NoMemory();
121 return -1;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000122 }
123 new->po = po;
124 new->next = lop;
125 lop = new;
126 return 0;
127}
128
129/* Remove the panel object from lop */
130static void
131remove_lop(PyCursesPanelObject *po)
132{
133 list_of_panels *temp, *n;
134
135 temp = lop;
136 if (temp->po == po) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 lop = temp->next;
Victor Stinnerb6404912013-07-07 16:21:41 +0200138 PyMem_Free(temp);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 return;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000140 }
Thomas Wouters47f003d2006-03-07 13:38:14 +0000141 while (temp->next == NULL || temp->next->po != po) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 if (temp->next == NULL) {
143 PyErr_SetString(PyExc_RuntimeError,
144 "remove_lop: can't find Panel Object");
145 return;
146 }
147 temp = temp->next;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000148 }
149 n = temp->next->next;
Victor Stinnerb6404912013-07-07 16:21:41 +0200150 PyMem_Free(temp->next);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000151 temp->next = n;
152 return;
153}
154
155/* Return the panel object that corresponds to pan */
156static PyCursesPanelObject *
157find_po(PANEL *pan)
158{
159 list_of_panels *temp;
160 for (temp = lop; temp->po->pan != pan; temp = temp->next)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000161 if (temp->next == NULL) return NULL; /* not found!? */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000162 return temp->po;
163}
164
165/* Function Prototype Macros - They are ugly but very, very useful. ;-)
166
167 X - function name
168 TYPE - parameter Type
169 ERGSTR - format string for construction of the return value
170 PARSESTR - format string for argument parsing */
171
172#define Panel_NoArgNoReturnFunction(X) \
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000173static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self) \
174{ return PyCursesCheckERR(X(self->pan), # X); }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000175
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000176#define Panel_NoArgTrueFalseFunction(X) \
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000177static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self) \
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000178{ \
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200179 if (X (self->pan) == FALSE) { Py_RETURN_FALSE; } \
180 else { Py_RETURN_TRUE; } }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000181
182#define Panel_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \
Fred Drake4e36d582000-12-23 05:46:23 +0000183static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self, PyObject *args) \
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000184{ \
185 TYPE arg1, arg2; \
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000186 if (!PyArg_ParseTuple(args, PARSESTR, &arg1, &arg2)) return NULL; \
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000187 return PyCursesCheckERR(X(self->pan, arg1, arg2), # X); }
188
189/* ------------- PANEL routines --------------- */
190
191Panel_NoArgNoReturnFunction(bottom_panel)
192Panel_NoArgNoReturnFunction(hide_panel)
193Panel_NoArgNoReturnFunction(show_panel)
194Panel_NoArgNoReturnFunction(top_panel)
195Panel_NoArgTrueFalseFunction(panel_hidden)
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000196Panel_TwoArgNoReturnFunction(move_panel, int, "ii;y,x")
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000197
198/* Allocation and deallocation of Panel Objects */
199
200static PyObject *
201PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
202{
203 PyCursesPanelObject *po;
204
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200205 po = PyObject_NEW(PyCursesPanelObject,
206 (PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000207 if (po == NULL) return NULL;
208 po->pan = pan;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000209 if (insert_lop(po) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 po->wo = NULL;
211 Py_DECREF(po);
212 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000213 }
Victor Stinnera7612272010-03-03 21:56:53 +0000214 po->wo = wo;
215 Py_INCREF(wo);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000216 return (PyObject *)po;
217}
218
219static void
220PyCursesPanel_Dealloc(PyCursesPanelObject *po)
221{
Serhiy Storchakadf40b622016-05-09 00:11:59 +0300222 PyObject *obj = (PyObject *) panel_userptr(po->pan);
223 if (obj) {
224 (void)set_panel_userptr(po->pan, NULL);
225 Py_DECREF(obj);
226 }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000227 (void)del_panel(po->pan);
Victor Stinnera7612272010-03-03 21:56:53 +0000228 if (po->wo != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000229 Py_DECREF(po->wo);
230 remove_lop(po);
Victor Stinnera7612272010-03-03 21:56:53 +0000231 }
Michael W. Hudsoncf6bfe42002-01-30 15:47:34 +0000232 PyObject_DEL(po);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000233}
234
235/* panel_above(NULL) returns the bottom panel in the stack. To get
236 this behaviour we use curses.panel.bottom_panel(). */
237static PyObject *
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000238PyCursesPanel_above(PyCursesPanelObject *self)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000239{
240 PANEL *pan;
241 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000243 pan = panel_above(self->pan);
244
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 if (pan == NULL) { /* valid output, it means the calling panel
246 is on top of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200247 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000248 }
249 po = find_po(pan);
250 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 PyErr_SetString(PyExc_RuntimeError,
252 "panel_above: can't find Panel Object");
253 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000254 }
255 Py_INCREF(po);
256 return (PyObject *)po;
257}
258
259/* panel_below(NULL) returns the top panel in the stack. To get
Andrew M. Kuchlingae89af92001-01-19 15:35:26 +0000260 this behaviour we use curses.panel.top_panel(). */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000261static PyObject *
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000262PyCursesPanel_below(PyCursesPanelObject *self)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000263{
264 PANEL *pan;
265 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000267 pan = panel_below(self->pan);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268
269 if (pan == NULL) { /* valid output, it means the calling panel
270 is on the bottom of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200271 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000272 }
273 po = find_po(pan);
274 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 PyErr_SetString(PyExc_RuntimeError,
276 "panel_below: can't find Panel Object");
277 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000278 }
279 Py_INCREF(po);
280 return (PyObject *)po;
281}
282
283static PyObject *
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000284PyCursesPanel_window(PyCursesPanelObject *self)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000285{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000286 Py_INCREF(self->wo);
287 return (PyObject *)self->wo;
288}
289
290static PyObject *
291PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args)
292{
293 PyCursesPanelObject *po;
294 PyCursesWindowObject *temp;
295 int rtn;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000297 if (PyTuple_Size(args) != 1) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 PyErr_SetString(PyExc_TypeError, "replace requires one argument");
299 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000300 }
301 if (!PyArg_ParseTuple(args, "O!;window object",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 &PyCursesWindow_Type, &temp))
303 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000304
305 po = find_po(self->pan);
306 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000307 PyErr_SetString(PyExc_RuntimeError,
308 "replace_panel: can't find Panel Object");
309 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000310 }
311
312 rtn = replace_panel(self->pan, temp->win);
313 if (rtn == ERR) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200314 PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000316 }
Serhiy Storchaka5a57ade2015-12-24 10:35:59 +0200317 Py_INCREF(temp);
Serhiy Storchaka57a01d32016-04-10 18:05:40 +0300318 Py_SETREF(po->wo, temp);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200319 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000320}
321
322static PyObject *
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000323PyCursesPanel_set_panel_userptr(PyCursesPanelObject *self, PyObject *obj)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000324{
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400325 PyObject *oldobj;
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400326 int rc;
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400327 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000328 Py_INCREF(obj);
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400329 oldobj = (PyObject *) panel_userptr(self->pan);
330 rc = set_panel_userptr(self->pan, (void*)obj);
331 if (rc == ERR) {
332 /* In case of an ncurses error, decref the new object again */
333 Py_DECREF(obj);
334 }
335 Py_XDECREF(oldobj);
336 return PyCursesCheckERR(rc, "set_panel_userptr");
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000337}
338
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000339static PyObject *
340PyCursesPanel_userptr(PyCursesPanelObject *self)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000341{
342 PyObject *obj;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 PyCursesInitialised;
Fred Drake4e36d582000-12-23 05:46:23 +0000344 obj = (PyObject *) panel_userptr(self->pan);
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000345 if (obj == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200346 PyErr_SetString(_curses_panelstate_global->PyCursesError, "no userptr set");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 return NULL;
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000348 }
349
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000350 Py_INCREF(obj);
351 return obj;
352}
353
354
355/* Module interface */
356
357static PyMethodDef PyCursesPanel_Methods[] = {
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000358 {"above", (PyCFunction)PyCursesPanel_above, METH_NOARGS},
359 {"below", (PyCFunction)PyCursesPanel_below, METH_NOARGS},
360 {"bottom", (PyCFunction)PyCursesPanel_bottom_panel, METH_NOARGS},
361 {"hidden", (PyCFunction)PyCursesPanel_panel_hidden, METH_NOARGS},
362 {"hide", (PyCFunction)PyCursesPanel_hide_panel, METH_NOARGS},
363 {"move", (PyCFunction)PyCursesPanel_move_panel, METH_VARARGS},
Neal Norwitz01b26942002-03-31 14:55:17 +0000364 {"replace", (PyCFunction)PyCursesPanel_replace_panel, METH_VARARGS},
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000365 {"set_userptr", (PyCFunction)PyCursesPanel_set_panel_userptr, METH_O},
366 {"show", (PyCFunction)PyCursesPanel_show_panel, METH_NOARGS},
367 {"top", (PyCFunction)PyCursesPanel_top_panel, METH_NOARGS},
368 {"userptr", (PyCFunction)PyCursesPanel_userptr, METH_NOARGS},
369 {"window", (PyCFunction)PyCursesPanel_window, METH_NOARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000371};
372
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000373/* -------------------------------------------------------*/
374
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200375static PyType_Slot PyCursesPanel_Type_slots[] = {
376 {Py_tp_dealloc, PyCursesPanel_Dealloc},
377 {Py_tp_methods, PyCursesPanel_Methods},
378 {0, 0},
379};
380
381static PyType_Spec PyCursesPanel_Type_spec = {
382 "_curses_panel.curses panel",
383 sizeof(PyCursesPanelObject),
384 0,
385 Py_TPFLAGS_DEFAULT,
386 PyCursesPanel_Type_slots
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000387};
388
389/* Wrapper for panel_above(NULL). This function returns the bottom
390 panel of the stack, so it's renamed to bottom_panel().
391 panel.above() *requires* a panel object in the first place which
392 may be undesirable. */
393static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000394PyCurses_bottom_panel(PyObject *self)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000395{
396 PANEL *pan;
397 PyCursesPanelObject *po;
398
399 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000400
401 pan = panel_above(NULL);
402
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000403 if (pan == NULL) { /* valid output, it means
404 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200405 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000406 }
407 po = find_po(pan);
408 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000409 PyErr_SetString(PyExc_RuntimeError,
410 "panel_above: can't find Panel Object");
411 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000412 }
413 Py_INCREF(po);
414 return (PyObject *)po;
415}
416
417static PyObject *
418PyCurses_new_panel(PyObject *self, PyObject *args)
419{
420 PyCursesWindowObject *win;
421 PANEL *pan;
422
Fred Drake4e36d582000-12-23 05:46:23 +0000423 if (!PyArg_ParseTuple(args, "O!", &PyCursesWindow_Type, &win))
424 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000425 pan = new_panel(win->win);
426 if (pan == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200427 PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000429 }
430 return (PyObject *)PyCursesPanel_New(pan, win);
431}
432
433
434/* Wrapper for panel_below(NULL). This function returns the top panel
435 of the stack, so it's renamed to top_panel(). panel.below()
436 *requires* a panel object in the first place which may be
437 undesirable. */
438static PyObject *
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000439PyCurses_top_panel(PyObject *self)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000440{
441 PANEL *pan;
442 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000443
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000444 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000445
446 pan = panel_below(NULL);
447
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000448 if (pan == NULL) { /* valid output, it means
449 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200450 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000451 }
452 po = find_po(pan);
453 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 PyErr_SetString(PyExc_RuntimeError,
455 "panel_below: can't find Panel Object");
456 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000457 }
458 Py_INCREF(po);
459 return (PyObject *)po;
460}
461
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000462static PyObject *PyCurses_update_panels(PyObject *self)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000463{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000464 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000465 update_panels();
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200466 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000467}
468
469
470/* List of functions defined in the module */
471
472static PyMethodDef PyCurses_methods[] = {
Neal Norwitz3a6f9782002-03-25 20:46:46 +0000473 {"bottom_panel", (PyCFunction)PyCurses_bottom_panel, METH_NOARGS},
474 {"new_panel", (PyCFunction)PyCurses_new_panel, METH_VARARGS},
475 {"top_panel", (PyCFunction)PyCurses_top_panel, METH_NOARGS},
476 {"update_panels", (PyCFunction)PyCurses_update_panels, METH_NOARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000478};
479
480/* Initialization function for the module */
481
Martin v. Löwis1a214512008-06-11 05:26:20 +0000482
483static struct PyModuleDef _curses_panelmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000484 PyModuleDef_HEAD_INIT,
485 "_curses_panel",
486 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200487 sizeof(_curses_panelstate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 PyCurses_methods,
489 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200490 _curses_panel_traverse,
491 _curses_panel_clear,
492 _curses_panel_free
Martin v. Löwis1a214512008-06-11 05:26:20 +0000493};
494
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000495PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000496PyInit__curses_panel(void)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000497{
498 PyObject *m, *d, *v;
499
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000500 /* Create the module and add the functions */
Martin v. Löwis1a214512008-06-11 05:26:20 +0000501 m = PyModule_Create(&_curses_panelmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +0000502 if (m == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200503 goto fail;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000504 d = PyModule_GetDict(m);
505
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200506 /* Initialize object type */
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300507 v = PyType_FromSpec(&PyCursesPanel_Type_spec);
508 if (v == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200509 goto fail;
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300510 ((PyTypeObject *)v)->tp_new = NULL;
511 _curses_panelstate(m)->PyCursesPanel_Type = v;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200512
513 import_curses();
Victor Stinner569f3642013-07-18 02:31:21 +0200514 if (PyErr_Occurred())
515 goto fail;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200516
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000517 /* For exception _curses_panel.error */
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200518 _curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
519 PyDict_SetItemString(d, "error", _curses_panelstate(m)->PyCursesError);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000520
521 /* Make the version available */
Neal Norwitz53cbdaa2007-08-23 21:42:55 +0000522 v = PyUnicode_FromString(PyCursesVersion);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000523 PyDict_SetItemString(d, "version", v);
524 PyDict_SetItemString(d, "__version__", v);
525 Py_DECREF(v);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000526 return m;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200527 fail:
528 Py_XDECREF(m);
529 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000530}