blob: 53849e3a29cc0252e9e601d13aea7c248757d75b [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{
Eddie Elizondo364f0b02019-03-27 07:52:18 -0400253 PyObject *tp, *obj;
254
255 tp = (PyObject *) Py_TYPE(po);
256 obj = (PyObject *) panel_userptr(po->pan);
Serhiy Storchakadf40b622016-05-09 00:11:59 +0300257 if (obj) {
258 (void)set_panel_userptr(po->pan, NULL);
259 Py_DECREF(obj);
260 }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000261 (void)del_panel(po->pan);
Victor Stinnera7612272010-03-03 21:56:53 +0000262 if (po->wo != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 Py_DECREF(po->wo);
264 remove_lop(po);
Victor Stinnera7612272010-03-03 21:56:53 +0000265 }
Michael W. Hudsoncf6bfe42002-01-30 15:47:34 +0000266 PyObject_DEL(po);
Eddie Elizondo364f0b02019-03-27 07:52:18 -0400267 Py_DECREF(tp);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000268}
269
270/* panel_above(NULL) returns the bottom panel in the stack. To get
271 this behaviour we use curses.panel.bottom_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300272/*[clinic input]
273_curses_panel.panel.above
274
275Return the panel above the current panel.
276[clinic start generated code]*/
277
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000278static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300279_curses_panel_panel_above_impl(PyCursesPanelObject *self)
280/*[clinic end generated code: output=70ac06d25fd3b4da input=c059994022976788]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000281{
282 PANEL *pan;
283 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000285 pan = panel_above(self->pan);
286
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 if (pan == NULL) { /* valid output, it means the calling panel
288 is on top of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200289 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000290 }
291 po = find_po(pan);
292 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000293 PyErr_SetString(PyExc_RuntimeError,
294 "panel_above: can't find Panel Object");
295 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000296 }
297 Py_INCREF(po);
298 return (PyObject *)po;
299}
300
301/* panel_below(NULL) returns the top panel in the stack. To get
Andrew M. Kuchlingae89af92001-01-19 15:35:26 +0000302 this behaviour we use curses.panel.top_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300303/*[clinic input]
304_curses_panel.panel.below
305
306Return the panel below the current panel.
307[clinic start generated code]*/
308
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000309static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300310_curses_panel_panel_below_impl(PyCursesPanelObject *self)
311/*[clinic end generated code: output=282861122e06e3de input=cc08f61936d297c6]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000312{
313 PANEL *pan;
314 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000316 pan = panel_below(self->pan);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000317
318 if (pan == NULL) { /* valid output, it means the calling panel
319 is on the bottom of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200320 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000321 }
322 po = find_po(pan);
323 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324 PyErr_SetString(PyExc_RuntimeError,
325 "panel_below: can't find Panel Object");
326 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000327 }
328 Py_INCREF(po);
329 return (PyObject *)po;
330}
331
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300332/*[clinic input]
333_curses_panel.panel.hidden
334
335Return True if the panel is hidden (not visible), False otherwise.
336[clinic start generated code]*/
337
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000338static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300339_curses_panel_panel_hidden_impl(PyCursesPanelObject *self)
340/*[clinic end generated code: output=66eebd1ab4501a71 input=453d4b4fce25e21a]*/
341{
342 if (panel_hidden(self->pan))
343 Py_RETURN_TRUE;
344 else
345 Py_RETURN_FALSE;
346}
347
348/*[clinic input]
349_curses_panel.panel.move
350
351 y: int
352 x: int
353 /
354
355Move the panel to the screen coordinates (y, x).
356[clinic start generated code]*/
357
358static PyObject *
359_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x)
360/*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/
361{
362 return PyCursesCheckERR(move_panel(self->pan, y, x), "move_panel");
363}
364
365/*[clinic input]
366_curses_panel.panel.window
367
368Return the window object associated with the panel.
369[clinic start generated code]*/
370
371static PyObject *
372_curses_panel_panel_window_impl(PyCursesPanelObject *self)
373/*[clinic end generated code: output=5f05940d4106b4cb input=6067353d2c307901]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000374{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000375 Py_INCREF(self->wo);
376 return (PyObject *)self->wo;
377}
378
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300379/*[clinic input]
380_curses_panel.panel.replace
381
382 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
383 /
384
385Change the window associated with the panel to the window win.
386[clinic start generated code]*/
387
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000388static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300389_curses_panel_panel_replace_impl(PyCursesPanelObject *self,
390 PyCursesWindowObject *win)
391/*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000392{
393 PyCursesPanelObject *po;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000394 int rtn;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000396 po = find_po(self->pan);
397 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000398 PyErr_SetString(PyExc_RuntimeError,
399 "replace_panel: can't find Panel Object");
400 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000401 }
402
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300403 rtn = replace_panel(self->pan, win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000404 if (rtn == ERR) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200405 PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000407 }
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300408 Py_INCREF(win);
409 Py_SETREF(po->wo, win);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200410 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000411}
412
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300413/*[clinic input]
414_curses_panel.panel.set_userptr
415
416 obj: object
417 /
418
animalize463572c2019-02-25 07:18:48 +0800419Set the panel's user pointer to obj.
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300420[clinic start generated code]*/
421
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000422static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300423_curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyObject *obj)
animalize463572c2019-02-25 07:18:48 +0800424/*[clinic end generated code: output=6fb145b3af88cf4a input=d2c6a9dbefabbf39]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000425{
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400426 PyObject *oldobj;
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400427 int rc;
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400428 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000429 Py_INCREF(obj);
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400430 oldobj = (PyObject *) panel_userptr(self->pan);
431 rc = set_panel_userptr(self->pan, (void*)obj);
432 if (rc == ERR) {
433 /* In case of an ncurses error, decref the new object again */
434 Py_DECREF(obj);
435 }
436 Py_XDECREF(oldobj);
437 return PyCursesCheckERR(rc, "set_panel_userptr");
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000438}
439
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300440/*[clinic input]
441_curses_panel.panel.userptr
442
443Return the user pointer for the panel.
444[clinic start generated code]*/
445
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000446static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300447_curses_panel_panel_userptr_impl(PyCursesPanelObject *self)
448/*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000449{
450 PyObject *obj;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000451 PyCursesInitialised;
Fred Drake4e36d582000-12-23 05:46:23 +0000452 obj = (PyObject *) panel_userptr(self->pan);
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000453 if (obj == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200454 PyErr_SetString(_curses_panelstate_global->PyCursesError, "no userptr set");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000455 return NULL;
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000456 }
457
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000458 Py_INCREF(obj);
459 return obj;
460}
461
462
463/* Module interface */
464
465static PyMethodDef PyCursesPanel_Methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300466 _CURSES_PANEL_PANEL_ABOVE_METHODDEF
467 _CURSES_PANEL_PANEL_BELOW_METHODDEF
468 _CURSES_PANEL_PANEL_BOTTOM_METHODDEF
469 _CURSES_PANEL_PANEL_HIDDEN_METHODDEF
470 _CURSES_PANEL_PANEL_HIDE_METHODDEF
471 _CURSES_PANEL_PANEL_MOVE_METHODDEF
472 _CURSES_PANEL_PANEL_REPLACE_METHODDEF
473 _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF
474 _CURSES_PANEL_PANEL_SHOW_METHODDEF
475 _CURSES_PANEL_PANEL_TOP_METHODDEF
476 _CURSES_PANEL_PANEL_USERPTR_METHODDEF
477 _CURSES_PANEL_PANEL_WINDOW_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000479};
480
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000481/* -------------------------------------------------------*/
482
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200483static PyType_Slot PyCursesPanel_Type_slots[] = {
484 {Py_tp_dealloc, PyCursesPanel_Dealloc},
485 {Py_tp_methods, PyCursesPanel_Methods},
486 {0, 0},
487};
488
489static PyType_Spec PyCursesPanel_Type_spec = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300490 "_curses_panel.panel",
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200491 sizeof(PyCursesPanelObject),
492 0,
493 Py_TPFLAGS_DEFAULT,
494 PyCursesPanel_Type_slots
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000495};
496
497/* Wrapper for panel_above(NULL). This function returns the bottom
498 panel of the stack, so it's renamed to bottom_panel().
499 panel.above() *requires* a panel object in the first place which
500 may be undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300501/*[clinic input]
502_curses_panel.bottom_panel
503
504Return the bottom panel in the panel stack.
505[clinic start generated code]*/
506
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000507static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300508_curses_panel_bottom_panel_impl(PyObject *module)
509/*[clinic end generated code: output=3aba9f985f4c2bd0 input=634c2a8078b3d7e4]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000510{
511 PANEL *pan;
512 PyCursesPanelObject *po;
513
514 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000515
516 pan = panel_above(NULL);
517
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 if (pan == NULL) { /* valid output, it means
519 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200520 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000521 }
522 po = find_po(pan);
523 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000524 PyErr_SetString(PyExc_RuntimeError,
525 "panel_above: can't find Panel Object");
526 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000527 }
528 Py_INCREF(po);
529 return (PyObject *)po;
530}
531
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300532/*[clinic input]
533_curses_panel.new_panel
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000534
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300535 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
536 /
537
538Return a panel object, associating it with the given window win.
539[clinic start generated code]*/
540
541static PyObject *
542_curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win)
543/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/
544{
545 PANEL *pan = new_panel(win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000546 if (pan == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200547 PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000549 }
550 return (PyObject *)PyCursesPanel_New(pan, win);
551}
552
553
554/* Wrapper for panel_below(NULL). This function returns the top panel
555 of the stack, so it's renamed to top_panel(). panel.below()
556 *requires* a panel object in the first place which may be
557 undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300558/*[clinic input]
559_curses_panel.top_panel
560
561Return the top panel in the panel stack.
562[clinic start generated code]*/
563
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000564static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300565_curses_panel_top_panel_impl(PyObject *module)
566/*[clinic end generated code: output=86704988bea8508e input=e62d6278dba39e79]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000567{
568 PANEL *pan;
569 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000570
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000571 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000572
573 pan = panel_below(NULL);
574
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 if (pan == NULL) { /* valid output, it means
576 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200577 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000578 }
579 po = find_po(pan);
580 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 PyErr_SetString(PyExc_RuntimeError,
582 "panel_below: can't find Panel Object");
583 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000584 }
585 Py_INCREF(po);
586 return (PyObject *)po;
587}
588
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300589/*[clinic input]
590_curses_panel.update_panels
591
592Updates the virtual screen after changes in the panel stack.
593
animalize463572c2019-02-25 07:18:48 +0800594This does not call curses.doupdate(), so you'll have to do this yourself.
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300595[clinic start generated code]*/
596
597static PyObject *
598_curses_panel_update_panels_impl(PyObject *module)
animalize463572c2019-02-25 07:18:48 +0800599/*[clinic end generated code: output=2f3b4c2e03d90ded input=5299624c9a708621]*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000600{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000601 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000602 update_panels();
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200603 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000604}
605
606
607/* List of functions defined in the module */
608
609static PyMethodDef PyCurses_methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300610 _CURSES_PANEL_BOTTOM_PANEL_METHODDEF
611 _CURSES_PANEL_NEW_PANEL_METHODDEF
612 _CURSES_PANEL_TOP_PANEL_METHODDEF
613 _CURSES_PANEL_UPDATE_PANELS_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000614 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000615};
616
617/* Initialization function for the module */
618
Martin v. Löwis1a214512008-06-11 05:26:20 +0000619
620static struct PyModuleDef _curses_panelmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000621 PyModuleDef_HEAD_INIT,
622 "_curses_panel",
623 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200624 sizeof(_curses_panelstate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 PyCurses_methods,
626 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200627 _curses_panel_traverse,
628 _curses_panel_clear,
629 _curses_panel_free
Martin v. Löwis1a214512008-06-11 05:26:20 +0000630};
631
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000632PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000633PyInit__curses_panel(void)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000634{
635 PyObject *m, *d, *v;
636
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000637 /* Create the module and add the functions */
Martin v. Löwis1a214512008-06-11 05:26:20 +0000638 m = PyModule_Create(&_curses_panelmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +0000639 if (m == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200640 goto fail;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000641 d = PyModule_GetDict(m);
642
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200643 /* Initialize object type */
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300644 v = PyType_FromSpec(&PyCursesPanel_Type_spec);
645 if (v == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200646 goto fail;
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300647 ((PyTypeObject *)v)->tp_new = NULL;
648 _curses_panelstate(m)->PyCursesPanel_Type = v;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200649
650 import_curses();
Victor Stinner569f3642013-07-18 02:31:21 +0200651 if (PyErr_Occurred())
652 goto fail;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200653
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000654 /* For exception _curses_panel.error */
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200655 _curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
656 PyDict_SetItemString(d, "error", _curses_panelstate(m)->PyCursesError);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000657
658 /* Make the version available */
Neal Norwitz53cbdaa2007-08-23 21:42:55 +0000659 v = PyUnicode_FromString(PyCursesVersion);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000660 PyDict_SetItemString(d, "version", v);
661 PyDict_SetItemString(d, "__version__", v);
662 Py_DECREF(v);
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300663
664 Py_INCREF(_curses_panelstate(m)->PyCursesPanel_Type);
665 PyModule_AddObject(m, "panel", (PyObject *)_curses_panelstate(m)->PyCursesPanel_Type);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000666 return m;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200667 fail:
668 Py_XDECREF(m);
669 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000670}