blob: f124803493d88b5eafb46572a199880125b4e903 [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
Hai Shif707d942020-03-16 21:15:01 +080024static inline _curses_panelstate*
25get_curses_panelstate(PyObject *module)
26{
27 void *state = PyModule_GetState(module);
28 assert(state != NULL);
29 return (_curses_panelstate *)state;
30}
Martin v. Löwisc838ec12012-06-14 16:00:24 +020031
Martin v. Löwisc838ec12012-06-14 16:00:24 +020032static int
33_curses_panel_clear(PyObject *m)
34{
Hai Shif707d942020-03-16 21:15:01 +080035 Py_CLEAR(get_curses_panelstate(m)->PyCursesError);
Martin v. Löwisc838ec12012-06-14 16:00:24 +020036 return 0;
37}
38
39static int
40_curses_panel_traverse(PyObject *m, visitproc visit, void *arg)
41{
Miss Islington (bot)bcbe5c52020-05-28 08:12:23 -070042 Py_VISIT(Py_TYPE(m));
Hai Shif707d942020-03-16 21:15:01 +080043 Py_VISIT(get_curses_panelstate(m)->PyCursesError);
Martin v. Löwisc838ec12012-06-14 16:00:24 +020044 return 0;
45}
46
47static void
48_curses_panel_free(void *m)
49{
50 _curses_panel_clear((PyObject *) m);
51}
52
53static struct PyModuleDef _curses_panelmodule;
54
55#define _curses_panelstate_global \
56((_curses_panelstate *) PyModule_GetState(PyState_FindModule(&_curses_panelmodule)))
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000057
58/* Utility Functions */
59
60/*
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000061 * Check the return code from a curses function and return None
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000062 * or raise an exception as appropriate.
63 */
64
65static PyObject *
Serhiy Storchakaef1585e2015-12-25 20:01:53 +020066PyCursesCheckERR(int code, const char *fname)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000067{
68 if (code != ERR) {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +020069 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000070 } else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 if (fname == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +020072 PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_ERR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 } else {
Martin v. Löwisc838ec12012-06-14 16:00:24 +020074 PyErr_Format(_curses_panelstate_global->PyCursesError, "%s() returned ERR", fname);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000075 }
76 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000077 }
78}
79
80/*****************************************************************************
81 The Panel Object
82******************************************************************************/
83
84/* Definition of the panel object and panel type */
85
86typedef struct {
87 PyObject_HEAD
88 PANEL *pan;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000089 PyCursesWindowObject *wo; /* for reference counts */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000090} PyCursesPanelObject;
91
Martin v. Löwisbc07cb82012-06-14 16:01:23 +020092#define PyCursesPanel_Check(v) \
Dong-hee Na1b55b652020-02-17 19:09:15 +090093 Py_IS_TYPE(v, _curses_panelstate_global->PyCursesPanel_Type)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000094
95/* Some helper functions. The problem is that there's always a window
96 associated with a panel. To ensure that Python's GC doesn't pull
97 this window from under our feet we need to keep track of references
98 to the corresponding window object within Python. We can't use
99 dupwin(oldwin) to keep a copy of the curses WINDOW because the
100 contents of oldwin is copied only once; code like
101
102 win = newwin(...)
103 pan = win.panel()
104 win.addstr(some_string)
105 pan.window().addstr(other_string)
106
107 will fail. */
108
109/* We keep a linked list of PyCursesPanelObjects, lop. A list should
110 suffice, I don't expect more than a handful or at most a few
111 dozens of panel objects within a typical program. */
112typedef struct _list_of_panels {
113 PyCursesPanelObject *po;
114 struct _list_of_panels *next;
115} list_of_panels;
116
117/* list anchor */
118static list_of_panels *lop;
119
120/* Insert a new panel object into lop */
121static int
122insert_lop(PyCursesPanelObject *po)
123{
124 list_of_panels *new;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000125
Victor Stinnerb6404912013-07-07 16:21:41 +0200126 if ((new = (list_of_panels *)PyMem_Malloc(sizeof(list_of_panels))) == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 PyErr_NoMemory();
128 return -1;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000129 }
130 new->po = po;
131 new->next = lop;
132 lop = new;
133 return 0;
134}
135
136/* Remove the panel object from lop */
137static void
138remove_lop(PyCursesPanelObject *po)
139{
140 list_of_panels *temp, *n;
141
142 temp = lop;
143 if (temp->po == po) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 lop = temp->next;
Victor Stinnerb6404912013-07-07 16:21:41 +0200145 PyMem_Free(temp);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000146 return;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000147 }
Thomas Wouters47f003d2006-03-07 13:38:14 +0000148 while (temp->next == NULL || temp->next->po != po) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 if (temp->next == NULL) {
150 PyErr_SetString(PyExc_RuntimeError,
151 "remove_lop: can't find Panel Object");
152 return;
153 }
154 temp = temp->next;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000155 }
156 n = temp->next->next;
Victor Stinnerb6404912013-07-07 16:21:41 +0200157 PyMem_Free(temp->next);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000158 temp->next = n;
159 return;
160}
161
162/* Return the panel object that corresponds to pan */
163static PyCursesPanelObject *
164find_po(PANEL *pan)
165{
166 list_of_panels *temp;
167 for (temp = lop; temp->po->pan != pan; temp = temp->next)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000168 if (temp->next == NULL) return NULL; /* not found!? */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000169 return temp->po;
170}
171
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300172/*[clinic input]
173module _curses_panel
174class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
175[clinic start generated code]*/
176/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2f4ef263ca850a31]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000177
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300178#include "clinic/_curses_panel.c.h"
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000179
180/* ------------- PANEL routines --------------- */
181
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300182/*[clinic input]
183_curses_panel.panel.bottom
184
185Push the panel to the bottom of the stack.
186[clinic start generated code]*/
187
188static PyObject *
189_curses_panel_panel_bottom_impl(PyCursesPanelObject *self)
190/*[clinic end generated code: output=7aa7d14d7e1d1ce6 input=b6c920c071b61e2e]*/
191{
192 return PyCursesCheckERR(bottom_panel(self->pan), "bottom");
193}
194
195/*[clinic input]
196_curses_panel.panel.hide
197
198Hide the panel.
199
200This does not delete the object, it just makes the window on screen invisible.
201[clinic start generated code]*/
202
203static PyObject *
204_curses_panel_panel_hide_impl(PyCursesPanelObject *self)
205/*[clinic end generated code: output=a7bbbd523e1eab49 input=f6ab884e99386118]*/
206{
207 return PyCursesCheckERR(hide_panel(self->pan), "hide");
208}
209
210/*[clinic input]
211_curses_panel.panel.show
212
213Display the panel (which might have been hidden).
214[clinic start generated code]*/
215
216static PyObject *
217_curses_panel_panel_show_impl(PyCursesPanelObject *self)
218/*[clinic end generated code: output=6b4553ab45c97769 input=57b167bbefaa3755]*/
219{
220 return PyCursesCheckERR(show_panel(self->pan), "show");
221}
222
223/*[clinic input]
224_curses_panel.panel.top
225
226Push panel to the top of the stack.
227[clinic start generated code]*/
228
229static PyObject *
230_curses_panel_panel_top_impl(PyCursesPanelObject *self)
231/*[clinic end generated code: output=0f5f2f8cdd2d1777 input=be33975ec3ca0e9a]*/
232{
233 return PyCursesCheckERR(top_panel(self->pan), "top");
234}
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000235
236/* Allocation and deallocation of Panel Objects */
237
238static PyObject *
239PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo)
240{
241 PyCursesPanelObject *po;
242
Victor Stinner92055202020-04-08 00:38:15 +0200243 po = PyObject_New(PyCursesPanelObject,
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200244 (PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000245 if (po == NULL) return NULL;
246 po->pan = pan;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000247 if (insert_lop(po) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 po->wo = NULL;
249 Py_DECREF(po);
250 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000251 }
Victor Stinnera7612272010-03-03 21:56:53 +0000252 po->wo = wo;
253 Py_INCREF(wo);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000254 return (PyObject *)po;
255}
256
257static void
258PyCursesPanel_Dealloc(PyCursesPanelObject *po)
259{
Eddie Elizondo364f0b02019-03-27 07:52:18 -0400260 PyObject *tp, *obj;
261
262 tp = (PyObject *) Py_TYPE(po);
263 obj = (PyObject *) panel_userptr(po->pan);
Serhiy Storchakadf40b622016-05-09 00:11:59 +0300264 if (obj) {
265 (void)set_panel_userptr(po->pan, NULL);
266 Py_DECREF(obj);
267 }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000268 (void)del_panel(po->pan);
Victor Stinnera7612272010-03-03 21:56:53 +0000269 if (po->wo != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 Py_DECREF(po->wo);
271 remove_lop(po);
Victor Stinnera7612272010-03-03 21:56:53 +0000272 }
Michael W. Hudsoncf6bfe42002-01-30 15:47:34 +0000273 PyObject_DEL(po);
Eddie Elizondo364f0b02019-03-27 07:52:18 -0400274 Py_DECREF(tp);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000275}
276
277/* panel_above(NULL) returns the bottom panel in the stack. To get
278 this behaviour we use curses.panel.bottom_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300279/*[clinic input]
280_curses_panel.panel.above
281
282Return the panel above the current panel.
283[clinic start generated code]*/
284
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000285static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300286_curses_panel_panel_above_impl(PyCursesPanelObject *self)
287/*[clinic end generated code: output=70ac06d25fd3b4da input=c059994022976788]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000288{
289 PANEL *pan;
290 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000292 pan = panel_above(self->pan);
293
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 if (pan == NULL) { /* valid output, it means the calling panel
295 is on top of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200296 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000297 }
298 po = find_po(pan);
299 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000300 PyErr_SetString(PyExc_RuntimeError,
301 "panel_above: can't find Panel Object");
302 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000303 }
304 Py_INCREF(po);
305 return (PyObject *)po;
306}
307
308/* panel_below(NULL) returns the top panel in the stack. To get
Andrew M. Kuchlingae89af92001-01-19 15:35:26 +0000309 this behaviour we use curses.panel.top_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300310/*[clinic input]
311_curses_panel.panel.below
312
313Return the panel below the current panel.
314[clinic start generated code]*/
315
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000316static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300317_curses_panel_panel_below_impl(PyCursesPanelObject *self)
318/*[clinic end generated code: output=282861122e06e3de input=cc08f61936d297c6]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000319{
320 PANEL *pan;
321 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000323 pan = panel_below(self->pan);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324
325 if (pan == NULL) { /* valid output, it means the calling panel
326 is on the bottom of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200327 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000328 }
329 po = find_po(pan);
330 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 PyErr_SetString(PyExc_RuntimeError,
332 "panel_below: can't find Panel Object");
333 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000334 }
335 Py_INCREF(po);
336 return (PyObject *)po;
337}
338
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300339/*[clinic input]
340_curses_panel.panel.hidden
341
342Return True if the panel is hidden (not visible), False otherwise.
343[clinic start generated code]*/
344
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000345static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300346_curses_panel_panel_hidden_impl(PyCursesPanelObject *self)
347/*[clinic end generated code: output=66eebd1ab4501a71 input=453d4b4fce25e21a]*/
348{
349 if (panel_hidden(self->pan))
350 Py_RETURN_TRUE;
351 else
352 Py_RETURN_FALSE;
353}
354
355/*[clinic input]
356_curses_panel.panel.move
357
358 y: int
359 x: int
360 /
361
362Move the panel to the screen coordinates (y, x).
363[clinic start generated code]*/
364
365static PyObject *
366_curses_panel_panel_move_impl(PyCursesPanelObject *self, int y, int x)
367/*[clinic end generated code: output=d867535a89777415 input=e0b36b78acc03fba]*/
368{
369 return PyCursesCheckERR(move_panel(self->pan, y, x), "move_panel");
370}
371
372/*[clinic input]
373_curses_panel.panel.window
374
375Return the window object associated with the panel.
376[clinic start generated code]*/
377
378static PyObject *
379_curses_panel_panel_window_impl(PyCursesPanelObject *self)
380/*[clinic end generated code: output=5f05940d4106b4cb input=6067353d2c307901]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000381{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000382 Py_INCREF(self->wo);
383 return (PyObject *)self->wo;
384}
385
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300386/*[clinic input]
387_curses_panel.panel.replace
388
389 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
390 /
391
392Change the window associated with the panel to the window win.
393[clinic start generated code]*/
394
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000395static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300396_curses_panel_panel_replace_impl(PyCursesPanelObject *self,
397 PyCursesWindowObject *win)
398/*[clinic end generated code: output=2253a95f7b287255 input=4b1c4283987d9dfa]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000399{
400 PyCursesPanelObject *po;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000401 int rtn;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000402
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000403 po = find_po(self->pan);
404 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000405 PyErr_SetString(PyExc_RuntimeError,
406 "replace_panel: can't find Panel Object");
407 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000408 }
409
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300410 rtn = replace_panel(self->pan, win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000411 if (rtn == ERR) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200412 PyErr_SetString(_curses_panelstate_global->PyCursesError, "replace_panel() returned ERR");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000414 }
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300415 Py_INCREF(win);
416 Py_SETREF(po->wo, win);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200417 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000418}
419
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300420/*[clinic input]
421_curses_panel.panel.set_userptr
422
423 obj: object
424 /
425
animalize463572c2019-02-25 07:18:48 +0800426Set the panel's user pointer to obj.
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300427[clinic start generated code]*/
428
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000429static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300430_curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyObject *obj)
animalize463572c2019-02-25 07:18:48 +0800431/*[clinic end generated code: output=6fb145b3af88cf4a input=d2c6a9dbefabbf39]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000432{
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400433 PyObject *oldobj;
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400434 int rc;
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400435 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000436 Py_INCREF(obj);
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400437 oldobj = (PyObject *) panel_userptr(self->pan);
438 rc = set_panel_userptr(self->pan, (void*)obj);
439 if (rc == ERR) {
440 /* In case of an ncurses error, decref the new object again */
441 Py_DECREF(obj);
442 }
443 Py_XDECREF(oldobj);
444 return PyCursesCheckERR(rc, "set_panel_userptr");
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000445}
446
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300447/*[clinic input]
448_curses_panel.panel.userptr
449
450Return the user pointer for the panel.
451[clinic start generated code]*/
452
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000453static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300454_curses_panel_panel_userptr_impl(PyCursesPanelObject *self)
455/*[clinic end generated code: output=e849c307b5dc9237 input=f78b7a47aef0fd50]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000456{
457 PyObject *obj;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000458 PyCursesInitialised;
Fred Drake4e36d582000-12-23 05:46:23 +0000459 obj = (PyObject *) panel_userptr(self->pan);
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000460 if (obj == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200461 PyErr_SetString(_curses_panelstate_global->PyCursesError, "no userptr set");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 return NULL;
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000463 }
464
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000465 Py_INCREF(obj);
466 return obj;
467}
468
469
470/* Module interface */
471
472static PyMethodDef PyCursesPanel_Methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300473 _CURSES_PANEL_PANEL_ABOVE_METHODDEF
474 _CURSES_PANEL_PANEL_BELOW_METHODDEF
475 _CURSES_PANEL_PANEL_BOTTOM_METHODDEF
476 _CURSES_PANEL_PANEL_HIDDEN_METHODDEF
477 _CURSES_PANEL_PANEL_HIDE_METHODDEF
478 _CURSES_PANEL_PANEL_MOVE_METHODDEF
479 _CURSES_PANEL_PANEL_REPLACE_METHODDEF
480 _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF
481 _CURSES_PANEL_PANEL_SHOW_METHODDEF
482 _CURSES_PANEL_PANEL_TOP_METHODDEF
483 _CURSES_PANEL_PANEL_USERPTR_METHODDEF
484 _CURSES_PANEL_PANEL_WINDOW_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000486};
487
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000488/* -------------------------------------------------------*/
489
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200490static PyType_Slot PyCursesPanel_Type_slots[] = {
491 {Py_tp_dealloc, PyCursesPanel_Dealloc},
492 {Py_tp_methods, PyCursesPanel_Methods},
493 {0, 0},
494};
495
496static PyType_Spec PyCursesPanel_Type_spec = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300497 "_curses_panel.panel",
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200498 sizeof(PyCursesPanelObject),
499 0,
500 Py_TPFLAGS_DEFAULT,
501 PyCursesPanel_Type_slots
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000502};
503
504/* Wrapper for panel_above(NULL). This function returns the bottom
505 panel of the stack, so it's renamed to bottom_panel().
506 panel.above() *requires* a panel object in the first place which
507 may be undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300508/*[clinic input]
509_curses_panel.bottom_panel
510
511Return the bottom panel in the panel stack.
512[clinic start generated code]*/
513
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000514static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300515_curses_panel_bottom_panel_impl(PyObject *module)
516/*[clinic end generated code: output=3aba9f985f4c2bd0 input=634c2a8078b3d7e4]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000517{
518 PANEL *pan;
519 PyCursesPanelObject *po;
520
521 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000522
523 pan = panel_above(NULL);
524
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000525 if (pan == NULL) { /* valid output, it means
526 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200527 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000528 }
529 po = find_po(pan);
530 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000531 PyErr_SetString(PyExc_RuntimeError,
532 "panel_above: can't find Panel Object");
533 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000534 }
535 Py_INCREF(po);
536 return (PyObject *)po;
537}
538
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300539/*[clinic input]
540_curses_panel.new_panel
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000541
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300542 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
543 /
544
545Return a panel object, associating it with the given window win.
546[clinic start generated code]*/
547
548static PyObject *
549_curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win)
550/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/
551{
552 PANEL *pan = new_panel(win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000553 if (pan == NULL) {
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200554 PyErr_SetString(_curses_panelstate_global->PyCursesError, catchall_NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000556 }
557 return (PyObject *)PyCursesPanel_New(pan, win);
558}
559
560
561/* Wrapper for panel_below(NULL). This function returns the top panel
562 of the stack, so it's renamed to top_panel(). panel.below()
563 *requires* a panel object in the first place which may be
564 undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300565/*[clinic input]
566_curses_panel.top_panel
567
568Return the top panel in the panel stack.
569[clinic start generated code]*/
570
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000571static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300572_curses_panel_top_panel_impl(PyObject *module)
573/*[clinic end generated code: output=86704988bea8508e input=e62d6278dba39e79]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000574{
575 PANEL *pan;
576 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000577
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000578 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000579
580 pan = panel_below(NULL);
581
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000582 if (pan == NULL) { /* valid output, it means
583 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200584 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000585 }
586 po = find_po(pan);
587 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 PyErr_SetString(PyExc_RuntimeError,
589 "panel_below: can't find Panel Object");
590 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000591 }
592 Py_INCREF(po);
593 return (PyObject *)po;
594}
595
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300596/*[clinic input]
597_curses_panel.update_panels
598
599Updates the virtual screen after changes in the panel stack.
600
animalize463572c2019-02-25 07:18:48 +0800601This does not call curses.doupdate(), so you'll have to do this yourself.
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300602[clinic start generated code]*/
603
604static PyObject *
605_curses_panel_update_panels_impl(PyObject *module)
animalize463572c2019-02-25 07:18:48 +0800606/*[clinic end generated code: output=2f3b4c2e03d90ded input=5299624c9a708621]*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000607{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000608 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000609 update_panels();
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200610 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000611}
612
613
614/* List of functions defined in the module */
615
616static PyMethodDef PyCurses_methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300617 _CURSES_PANEL_BOTTOM_PANEL_METHODDEF
618 _CURSES_PANEL_NEW_PANEL_METHODDEF
619 _CURSES_PANEL_TOP_PANEL_METHODDEF
620 _CURSES_PANEL_UPDATE_PANELS_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000621 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000622};
623
624/* Initialization function for the module */
625
Martin v. Löwis1a214512008-06-11 05:26:20 +0000626
627static struct PyModuleDef _curses_panelmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000628 PyModuleDef_HEAD_INIT,
629 "_curses_panel",
630 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200631 sizeof(_curses_panelstate),
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000632 PyCurses_methods,
633 NULL,
Martin v. Löwisc838ec12012-06-14 16:00:24 +0200634 _curses_panel_traverse,
635 _curses_panel_clear,
636 _curses_panel_free
Martin v. Löwis1a214512008-06-11 05:26:20 +0000637};
638
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000639PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000640PyInit__curses_panel(void)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000641{
642 PyObject *m, *d, *v;
643
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000644 /* Create the module and add the functions */
Martin v. Löwis1a214512008-06-11 05:26:20 +0000645 m = PyModule_Create(&_curses_panelmodule);
Neal Norwitz1ac754f2006-01-19 06:09:39 +0000646 if (m == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200647 goto fail;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000648 d = PyModule_GetDict(m);
649
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200650 /* Initialize object type */
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300651 v = PyType_FromSpec(&PyCursesPanel_Type_spec);
652 if (v == NULL)
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200653 goto fail;
Serhiy Storchakae3f1b092016-05-08 20:46:22 +0300654 ((PyTypeObject *)v)->tp_new = NULL;
Hai Shif707d942020-03-16 21:15:01 +0800655 get_curses_panelstate(m)->PyCursesPanel_Type = v;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200656
657 import_curses();
Victor Stinner569f3642013-07-18 02:31:21 +0200658 if (PyErr_Occurred())
659 goto fail;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200660
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000661 /* For exception _curses_panel.error */
Hai Shif707d942020-03-16 21:15:01 +0800662 get_curses_panelstate(m)->PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL);
663 PyDict_SetItemString(d, "error", get_curses_panelstate(m)->PyCursesError);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000664
665 /* Make the version available */
Neal Norwitz53cbdaa2007-08-23 21:42:55 +0000666 v = PyUnicode_FromString(PyCursesVersion);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000667 PyDict_SetItemString(d, "version", v);
668 PyDict_SetItemString(d, "__version__", v);
669 Py_DECREF(v);
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300670
Hai Shif707d942020-03-16 21:15:01 +0800671 Py_INCREF(get_curses_panelstate(m)->PyCursesPanel_Type);
672 PyModule_AddObject(m, "panel",
673 (PyObject *)get_curses_panelstate(m)->PyCursesPanel_Type);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000674 return m;
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200675 fail:
676 Py_XDECREF(m);
677 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000678}