blob: 609718f65f15abb4cb48097fce8267bcc07db420 [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
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300165/*[clinic input]
166module _curses_panel
167class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
168[clinic start generated code]*/
169/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2f4ef263ca850a31]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000170
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300171#include "clinic/_curses_panel.c.h"
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000172
173/* ------------- PANEL routines --------------- */
174
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300175/*[clinic input]
176_curses_panel.panel.bottom
177
178Push the panel to the bottom of the stack.
179[clinic start generated code]*/
180
181static PyObject *
182_curses_panel_panel_bottom_impl(PyCursesPanelObject *self)
183/*[clinic end generated code: output=7aa7d14d7e1d1ce6 input=b6c920c071b61e2e]*/
184{
185 return PyCursesCheckERR(bottom_panel(self->pan), "bottom");
186}
187
188/*[clinic input]
189_curses_panel.panel.hide
190
191Hide the panel.
192
193This does not delete the object, it just makes the window on screen invisible.
194[clinic start generated code]*/
195
196static PyObject *
197_curses_panel_panel_hide_impl(PyCursesPanelObject *self)
198/*[clinic end generated code: output=a7bbbd523e1eab49 input=f6ab884e99386118]*/
199{
200 return PyCursesCheckERR(hide_panel(self->pan), "hide");
201}
202
203/*[clinic input]
204_curses_panel.panel.show
205
206Display the panel (which might have been hidden).
207[clinic start generated code]*/
208
209static PyObject *
210_curses_panel_panel_show_impl(PyCursesPanelObject *self)
211/*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/
212{
213 return PyCursesCheckERR(show_panel(self->pan), "show");
214}
215
216/*[clinic input]
217_curses_panel.panel.top
218
219Push panel to the top of the stack.
220[clinic start generated code]*/
221
222static PyObject *
223_curses_panel_panel_top_impl(PyCursesPanelObject *self)
224/*[clinic end generated code: output=0f5f2f8cdd2d1777 input=be33975ec3ca0e9a]*/
225{
226 return PyCursesCheckERR(top_panel(self->pan), "top");
227}
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000228
229/* Allocation and deallocation of Panel Objects */
230
231static PyObject *
232PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
233{
234 PyCursesPanelObject *po;
235
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200236 po = PyObject_NEW(PyCursesPanelObject,
237 (PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000238 if (po == NULL) return NULL;
239 po->pan = pan;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000240 if (insert_lop(po) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 po->wo = NULL;
242 Py_DECREF(po);
243 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000244 }
Victor Stinnera7612272010-03-03 21:56:53 +0000245 po->wo = wo;
246 Py_INCREF(wo);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000247 return (PyObject *)po;
248}
249
250static void
251PyCursesPanel_Dealloc(PyCursesPanelObject *po)
252{
Serhiy Storchakadf40b622016-05-09 00:11:59 +0300253 PyObject *obj = (PyObject *) panel_userptr(po->pan);
254 if (obj) {
255 (void)set_panel_userptr(po->pan, NULL);
256 Py_DECREF(obj);
257 }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000258 (void)del_panel(po->pan);
Victor Stinnera7612272010-03-03 21:56:53 +0000259 if (po->wo != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 Py_DECREF(po->wo);
261 remove_lop(po);
Victor Stinnera7612272010-03-03 21:56:53 +0000262 }
Michael W. Hudsoncf6bfe42002-01-30 15:47:34 +0000263 PyObject_DEL(po);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000264}
265
266/* panel_above(NULL) returns the bottom panel in the stack. To get
267 this behaviour we use curses.panel.bottom_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300268/*[clinic input]
269_curses_panel.panel.above
270
271Return the panel above the current panel.
272[clinic start generated code]*/
273
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000274static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300275_curses_panel_panel_above_impl(PyCursesPanelObject *self)
276/*[clinic end generated code: output=70ac06d25fd3b4da input=c059994022976788]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000277{
278 PANEL *pan;
279 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000281 pan = panel_above(self->pan);
282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 if (pan == NULL) { /* valid output, it means the calling panel
284 is on top of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200285 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000286 }
287 po = find_po(pan);
288 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000289 PyErr_SetString(PyExc_RuntimeError,
290 "panel_above: can't find Panel Object");
291 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000292 }
293 Py_INCREF(po);
294 return (PyObject *)po;
295}
296
297/* panel_below(NULL) returns the top panel in the stack. To get
Andrew M. Kuchlingae89af92001-01-19 15:35:26 +0000298 this behaviour we use curses.panel.top_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300299/*[clinic input]
300_curses_panel.panel.below
301
302Return the panel below the current panel.
303[clinic start generated code]*/
304
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000305static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300306_curses_panel_panel_below_impl(PyCursesPanelObject *self)
307/*[clinic end generated code: output=282861122e06e3de input=cc08f61936d297c6]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000308{
309 PANEL *pan;
310 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000312 pan = panel_below(self->pan);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000313
314 if (pan == NULL) { /* valid output, it means the calling panel
315 is on the bottom of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200316 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000317 }
318 po = find_po(pan);
319 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 PyErr_SetString(PyExc_RuntimeError,
321 "panel_below: can't find Panel Object");
322 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000323 }
324 Py_INCREF(po);
325 return (PyObject *)po;
326}
327
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300328/*[clinic input]
329_curses_panel.panel.hidden
330
331Return True if the panel is hidden (not visible), False otherwise.
332[clinic start generated code]*/
333
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000334static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300335_curses_panel_panel_hidden_impl(PyCursesPanelObject *self)
336/*[clinic end generated code: output=66eebd1ab4501a71 input=453d4b4fce25e21a]*/
337{
338 if (panel_hidden(self->pan))
339 Py_RETURN_TRUE;
340 else
341 Py_RETURN_FALSE;
342}
343
344/*[clinic input]
345_curses_panel.panel.move
346
347 y: int
348 x: int
349 /
350
351Move the panel to the screen coordinates (y, x).
352[clinic start generated code]*/
353
354static PyObject *
355_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x)
356/*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/
357{
358 return PyCursesCheckERR(move_panel(self->pan, y, x), "move_panel");
359}
360
361/*[clinic input]
362_curses_panel.panel.window
363
364Return the window object associated with the panel.
365[clinic start generated code]*/
366
367static PyObject *
368_curses_panel_panel_window_impl(PyCursesPanelObject *self)
369/*[clinic end generated code: output=5f05940d4106b4cb input=6067353d2c307901]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000370{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000371 Py_INCREF(self->wo);
372 return (PyObject *)self->wo;
373}
374
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300375/*[clinic input]
376_curses_panel.panel.replace
377
378 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
379 /
380
381Change the window associated with the panel to the window win.
382[clinic start generated code]*/
383
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000384static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300385_curses_panel_panel_replace_impl(PyCursesPanelObject *self,
386 PyCursesWindowObject *win)
387/*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000388{
389 PyCursesPanelObject *po;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000390 int rtn;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000392 po = find_po(self->pan);
393 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 PyErr_SetString(PyExc_RuntimeError,
395 "replace_panel: can't find Panel Object");
396 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000397 }
398
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300399 rtn = replace_panel(self->pan, win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000400 if (rtn == ERR) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200401 PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000402 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000403 }
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300404 Py_INCREF(win);
405 Py_SETREF(po->wo, win);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200406 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000407}
408
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300409/*[clinic input]
410_curses_panel.panel.set_userptr
411
412 obj: object
413 /
414
415Set the panel’s user pointer to obj.
416[clinic start generated code]*/
417
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000418static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300419_curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyObject *obj)
420/*[clinic end generated code: output=6fb145b3af88cf4a input=2056be1cd148b05c]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000421{
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400422 PyObject *oldobj;
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400423 int rc;
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400424 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000425 Py_INCREF(obj);
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400426 oldobj = (PyObject *) panel_userptr(self->pan);
427 rc = set_panel_userptr(self->pan, (void*)obj);
428 if (rc == ERR) {
429 /* In case of an ncurses error, decref the new object again */
430 Py_DECREF(obj);
431 }
432 Py_XDECREF(oldobj);
433 return PyCursesCheckERR(rc, "set_panel_userptr");
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000434}
435
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300436/*[clinic input]
437_curses_panel.panel.userptr
438
439Return the user pointer for the panel.
440[clinic start generated code]*/
441
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000442static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300443_curses_panel_panel_userptr_impl(PyCursesPanelObject *self)
444/*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000445{
446 PyObject *obj;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000447 PyCursesInitialised;
Fred Drake4e36d582000-12-23 05:46:23 +0000448 obj = (PyObject *) panel_userptr(self->pan);
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000449 if (obj == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200450 PyErr_SetString(_curses_panelstate_global->PyCursesError, "no userptr set");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000451 return NULL;
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000452 }
453
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000454 Py_INCREF(obj);
455 return obj;
456}
457
458
459/* Module interface */
460
461static PyMethodDef PyCursesPanel_Methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300462 _CURSES_PANEL_PANEL_ABOVE_METHODDEF
463 _CURSES_PANEL_PANEL_BELOW_METHODDEF
464 _CURSES_PANEL_PANEL_BOTTOM_METHODDEF
465 _CURSES_PANEL_PANEL_HIDDEN_METHODDEF
466 _CURSES_PANEL_PANEL_HIDE_METHODDEF
467 _CURSES_PANEL_PANEL_MOVE_METHODDEF
468 _CURSES_PANEL_PANEL_REPLACE_METHODDEF
469 _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF
470 _CURSES_PANEL_PANEL_SHOW_METHODDEF
471 _CURSES_PANEL_PANEL_TOP_METHODDEF
472 _CURSES_PANEL_PANEL_USERPTR_METHODDEF
473 _CURSES_PANEL_PANEL_WINDOW_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000474 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000475};
476
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000477/* -------------------------------------------------------*/
478
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200479static PyType_Slot PyCursesPanel_Type_slots[] = {
480 {Py_tp_dealloc, PyCursesPanel_Dealloc},
481 {Py_tp_methods, PyCursesPanel_Methods},
482 {0, 0},
483};
484
485static PyType_Spec PyCursesPanel_Type_spec = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300486 "_curses_panel.panel",
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200487 sizeof(PyCursesPanelObject),
488 0,
489 Py_TPFLAGS_DEFAULT,
490 PyCursesPanel_Type_slots
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000491};
492
493/* Wrapper for panel_above(NULL). This function returns the bottom
494 panel of the stack, so it's renamed to bottom_panel().
495 panel.above() *requires* a panel object in the first place which
496 may be undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300497/*[clinic input]
498_curses_panel.bottom_panel
499
500Return the bottom panel in the panel stack.
501[clinic start generated code]*/
502
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000503static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300504_curses_panel_bottom_panel_impl(PyObject *module)
505/*[clinic end generated code: output=3aba9f985f4c2bd0 input=634c2a8078b3d7e4]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000506{
507 PANEL *pan;
508 PyCursesPanelObject *po;
509
510 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000511
512 pan = panel_above(NULL);
513
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000514 if (pan == NULL) { /* valid output, it means
515 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200516 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000517 }
518 po = find_po(pan);
519 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000520 PyErr_SetString(PyExc_RuntimeError,
521 "panel_above: can't find Panel Object");
522 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000523 }
524 Py_INCREF(po);
525 return (PyObject *)po;
526}
527
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300528/*[clinic input]
529_curses_panel.new_panel
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000530
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300531 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
532 /
533
534Return a panel object, associating it with the given window win.
535[clinic start generated code]*/
536
537static PyObject *
538_curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win)
539/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/
540{
541 PANEL *pan = new_panel(win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000542 if (pan == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200543 PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000544 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000545 }
546 return (PyObject *)PyCursesPanel_New(pan, win);
547}
548
549
550/* Wrapper for panel_below(NULL). This function returns the top panel
551 of the stack, so it's renamed to top_panel(). panel.below()
552 *requires* a panel object in the first place which may be
553 undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300554/*[clinic input]
555_curses_panel.top_panel
556
557Return the top panel in the panel stack.
558[clinic start generated code]*/
559
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000560static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300561_curses_panel_top_panel_impl(PyObject *module)
562/*[clinic end generated code: output=86704988bea8508e input=e62d6278dba39e79]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000563{
564 PANEL *pan;
565 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000567 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000568
569 pan = panel_below(NULL);
570
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000571 if (pan == NULL) { /* valid output, it means
572 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200573 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000574 }
575 po = find_po(pan);
576 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000577 PyErr_SetString(PyExc_RuntimeError,
578 "panel_below: can't find Panel Object");
579 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000580 }
581 Py_INCREF(po);
582 return (PyObject *)po;
583}
584
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300585/*[clinic input]
586_curses_panel.update_panels
587
588Updates the virtual screen after changes in the panel stack.
589
590This does not call curses.doupdate(), so you’ll have to do this yourself.
591[clinic start generated code]*/
592
593static PyObject *
594_curses_panel_update_panels_impl(PyObject *module)
595/*[clinic end generated code: output=2f3b4c2e03d90ded input=a127069202b0a097]*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000596{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000597 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000598 update_panels();
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200599 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000600}
601
602
603/* List of functions defined in the module */
604
605static PyMethodDef PyCurses_methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300606 _CURSES_PANEL_BOTTOM_PANEL_METHODDEF
607 _CURSES_PANEL_NEW_PANEL_METHODDEF
608 _CURSES_PANEL_TOP_PANEL_METHODDEF
609 _CURSES_PANEL_UPDATE_PANELS_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000611};
612
613/* Initialization function for the module */
614
Martin v. Löwis1a214512008-06-11 05:26:20 +0000615
616static struct PyModuleDef _curses_panelmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000617 PyModuleDef_HEAD_INIT,
618 "_curses_panel",
619 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200620 sizeof(_curses_panelstate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000621 PyCurses_methods,
622 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200623 _curses_panel_traverse,
624 _curses_panel_clear,
625 _curses_panel_free
Martin v. Löwis1a214512008-06-11 05:26:20 +0000626};
627
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000628PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000629PyInit__curses_panel(void)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000630{
631 PyObject *m, *d, *v;
632
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000633 /* Create the module and add the functions */
Martin v. Löwis1a214512008-06-11 05:26:20 +0000634 m = PyModule_Create(&_curses_panelmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +0000635 if (m == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200636 goto fail;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000637 d = PyModule_GetDict(m);
638
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200639 /* Initialize object type */
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300640 v = PyType_FromSpec(&PyCursesPanel_Type_spec);
641 if (v == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200642 goto fail;
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300643 ((PyTypeObject *)v)->tp_new = NULL;
644 _curses_panelstate(m)->PyCursesPanel_Type = v;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200645
646 import_curses();
Victor Stinner569f3642013-07-18 02:31:21 +0200647 if (PyErr_Occurred())
648 goto fail;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200649
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000650 /* For exception _curses_panel.error */
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200651 _curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
652 PyDict_SetItemString(d, "error", _curses_panelstate(m)->PyCursesError);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000653
654 /* Make the version available */
Neal Norwitz53cbdaa2007-08-23 21:42:55 +0000655 v = PyUnicode_FromString(PyCursesVersion);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000656 PyDict_SetItemString(d, "version", v);
657 PyDict_SetItemString(d, "__version__", v);
658 Py_DECREF(v);
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300659
660 Py_INCREF(_curses_panelstate(m)->PyCursesPanel_Type);
661 PyModule_AddObject(m, "panel", (PyObject *)_curses_panelstate(m)->PyCursesPanel_Type);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000662 return m;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200663 fail:
664 Py_XDECREF(m);
665 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000666}