blob: d782ccd08679862f05da16e67a04c82e01fe7bee [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;
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050021 PyTypeObject *PyCursesPanel_Type;
22} _curses_panel_state;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000023
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050024static inline _curses_panel_state *
25get_curses_panel_state(PyObject *module)
Hai Shif707d942020-03-16 21:15:01 +080026{
27 void *state = PyModule_GetState(module);
28 assert(state != NULL);
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050029 return (_curses_panel_state *)state;
Hai Shif707d942020-03-16 21:15:01 +080030}
Martin v. Löwisc838ec12012-06-14 16:00:24 +020031
Martin v. Löwisc838ec12012-06-14 16:00:24 +020032static int
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050033_curses_panel_clear(PyObject *mod)
Martin v. Löwisc838ec12012-06-14 16:00:24 +020034{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050035 _curses_panel_state *state = get_curses_panel_state(mod);
36 Py_CLEAR(state->PyCursesError);
37 Py_CLEAR(state->PyCursesPanel_Type);
Martin v. Löwisc838ec12012-06-14 16:00:24 +020038 return 0;
39}
40
41static int
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050042_curses_panel_traverse(PyObject *mod, visitproc visit, void *arg)
Martin v. Löwisc838ec12012-06-14 16:00:24 +020043{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050044 Py_VISIT(Py_TYPE(mod));
45 _curses_panel_state *state = get_curses_panel_state(mod);
46 Py_VISIT(state->PyCursesError);
47 Py_VISIT(state->PyCursesPanel_Type);
Martin v. Löwisc838ec12012-06-14 16:00:24 +020048 return 0;
49}
50
51static void
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050052_curses_panel_free(void *mod)
Martin v. Löwisc838ec12012-06-14 16:00:24 +020053{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050054 _curses_panel_clear((PyObject *) mod);
Martin v. Löwisc838ec12012-06-14 16:00:24 +020055}
56
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000057/* Utility Functions */
58
59/*
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 * Check the return code from a curses function and return None
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000061 * or raise an exception as appropriate.
62 */
63
64static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050065PyCursesCheckERR(_curses_panel_state *state, int code, const char *fname)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000066{
67 if (code != ERR) {
Serhiy Storchaka228b12e2017-01-23 09:47:21 +020068 Py_RETURN_NONE;
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050069 }
70 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 if (fname == NULL) {
Mohamed Koubaa1baf0302020-09-07 10:14:25 -050072 PyErr_SetString(state->PyCursesError, catchall_ERR);
73 }
74 else {
75 PyErr_Format(state->PyCursesError, "%s() returned ERR", fname);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000076 }
77 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000078 }
79}
80
81/*****************************************************************************
82 The Panel Object
83******************************************************************************/
84
85/* Definition of the panel object and panel type */
86
87typedef struct {
88 PyObject_HEAD
89 PANEL *pan;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 PyCursesWindowObject *wo; /* for reference counts */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000091} PyCursesPanelObject;
92
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +000093/* Some helper functions. The problem is that there's always a window
94 associated with a panel. To ensure that Python's GC doesn't pull
95 this window from under our feet we need to keep track of references
96 to the corresponding window object within Python. We can't use
97 dupwin(oldwin) to keep a copy of the curses WINDOW because the
98 contents of oldwin is copied only once; code like
99
100 win = newwin(...)
101 pan = win.panel()
102 win.addstr(some_string)
103 pan.window().addstr(other_string)
104
105 will fail. */
106
107/* We keep a linked list of PyCursesPanelObjects, lop. A list should
108 suffice, I don't expect more than a handful or at most a few
109 dozens of panel objects within a typical program. */
110typedef struct _list_of_panels {
111 PyCursesPanelObject *po;
112 struct _list_of_panels *next;
113} list_of_panels;
114
115/* list anchor */
116static list_of_panels *lop;
117
118/* Insert a new panel object into lop */
119static int
120insert_lop(PyCursesPanelObject *po)
121{
122 list_of_panels *new;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000123
Victor Stinnerb6404912013-07-07 16:21:41 +0200124 if ((new = (list_of_panels *)PyMem_Malloc(sizeof(list_of_panels))) == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000125 PyErr_NoMemory();
126 return -1;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000127 }
128 new->po = po;
129 new->next = lop;
130 lop = new;
131 return 0;
132}
133
134/* Remove the panel object from lop */
135static void
136remove_lop(PyCursesPanelObject *po)
137{
138 list_of_panels *temp, *n;
139
140 temp = lop;
141 if (temp->po == po) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 lop = temp->next;
Victor Stinnerb6404912013-07-07 16:21:41 +0200143 PyMem_Free(temp);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 return;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000145 }
Thomas Wouters47f003d2006-03-07 13:38:14 +0000146 while (temp->next == NULL || temp->next->po != po) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 if (temp->next == NULL) {
148 PyErr_SetString(PyExc_RuntimeError,
149 "remove_lop: can't find Panel Object");
150 return;
151 }
152 temp = temp->next;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000153 }
154 n = temp->next->next;
Victor Stinnerb6404912013-07-07 16:21:41 +0200155 PyMem_Free(temp->next);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000156 temp->next = n;
157 return;
158}
159
160/* Return the panel object that corresponds to pan */
161static PyCursesPanelObject *
162find_po(PANEL *pan)
163{
164 list_of_panels *temp;
165 for (temp = lop; temp->po->pan != pan; temp = temp->next)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 if (temp->next == NULL) return NULL; /* not found!? */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000167 return temp->po;
168}
169
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300170/*[clinic input]
171module _curses_panel
172class _curses_panel.panel "PyCursesPanelObject *" "&PyCursesPanel_Type"
173[clinic start generated code]*/
174/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2f4ef263ca850a31]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000175
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300176#include "clinic/_curses_panel.c.h"
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000177
178/* ------------- PANEL routines --------------- */
179
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300180/*[clinic input]
181_curses_panel.panel.bottom
182
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500183 cls: defining_class
184
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300185Push the panel to the bottom of the stack.
186[clinic start generated code]*/
187
188static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500189_curses_panel_panel_bottom_impl(PyCursesPanelObject *self, PyTypeObject *cls)
190/*[clinic end generated code: output=8ec7fbbc08554021 input=6b7d2c0578b5a1c4]*/
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300191{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500192 _curses_panel_state *state = PyType_GetModuleState(cls);
193 return PyCursesCheckERR(state, bottom_panel(self->pan), "bottom");
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300194}
195
196/*[clinic input]
197_curses_panel.panel.hide
198
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500199 cls: defining_class
200
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300201Hide the panel.
202
203This does not delete the object, it just makes the window on screen invisible.
204[clinic start generated code]*/
205
206static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500207_curses_panel_panel_hide_impl(PyCursesPanelObject *self, PyTypeObject *cls)
208/*[clinic end generated code: output=cc6ab7203cdc1450 input=1bfc741f473e6055]*/
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300209{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500210 _curses_panel_state *state = PyType_GetModuleState(cls);
211 return PyCursesCheckERR(state, hide_panel(self->pan), "hide");
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300212}
213
214/*[clinic input]
215_curses_panel.panel.show
216
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500217 cls: defining_class
218
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300219Display the panel (which might have been hidden).
220[clinic start generated code]*/
221
222static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500223_curses_panel_panel_show_impl(PyCursesPanelObject *self, PyTypeObject *cls)
224/*[clinic end generated code: output=dc3421de375f0409 input=8122e80151cb4379]*/
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300225{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500226 _curses_panel_state *state = PyType_GetModuleState(cls);
227 return PyCursesCheckERR(state, show_panel(self->pan), "show");
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300228}
229
230/*[clinic input]
231_curses_panel.panel.top
232
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500233 cls: defining_class
234
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300235Push panel to the top of the stack.
236[clinic start generated code]*/
237
238static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500239_curses_panel_panel_top_impl(PyCursesPanelObject *self, PyTypeObject *cls)
240/*[clinic end generated code: output=10a072e511e873f7 input=1f372d597dda3379]*/
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300241{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500242 _curses_panel_state *state = PyType_GetModuleState(cls);
243 return PyCursesCheckERR(state, top_panel(self->pan), "top");
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300244}
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000245
246/* Allocation and deallocation of Panel Objects */
247
248static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500249PyCursesPanel_New(_curses_panel_state *state, PANEL *pan,
250 PyCursesWindowObject *wo)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000251{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500252 PyCursesPanelObject *po = PyObject_New(PyCursesPanelObject,
253 state->PyCursesPanel_Type);
254 if (po == NULL) {
255 return NULL;
256 }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000257
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000258 po->pan = pan;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000259 if (insert_lop(po) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 po->wo = NULL;
261 Py_DECREF(po);
262 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000263 }
Victor Stinnera7612272010-03-03 21:56:53 +0000264 po->wo = wo;
265 Py_INCREF(wo);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000266 return (PyObject *)po;
267}
268
269static void
270PyCursesPanel_Dealloc(PyCursesPanelObject *po)
271{
Eddie Elizondo364f0b02019-03-27 07:52:18 -0400272 PyObject *tp, *obj;
273
274 tp = (PyObject *) Py_TYPE(po);
275 obj = (PyObject *) panel_userptr(po->pan);
Serhiy Storchakadf40b622016-05-09 00:11:59 +0300276 if (obj) {
277 (void)set_panel_userptr(po->pan, NULL);
278 Py_DECREF(obj);
279 }
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000280 (void)del_panel(po->pan);
Victor Stinnera7612272010-03-03 21:56:53 +0000281 if (po->wo != NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 Py_DECREF(po->wo);
283 remove_lop(po);
Victor Stinnera7612272010-03-03 21:56:53 +0000284 }
Victor Stinner32bd68c2020-12-01 10:37:39 +0100285 PyObject_Free(po);
Eddie Elizondo364f0b02019-03-27 07:52:18 -0400286 Py_DECREF(tp);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000287}
288
289/* panel_above(NULL) returns the bottom panel in the stack. To get
290 this behaviour we use curses.panel.bottom_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300291/*[clinic input]
292_curses_panel.panel.above
293
294Return the panel above the current panel.
295[clinic start generated code]*/
296
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000297static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300298_curses_panel_panel_above_impl(PyCursesPanelObject *self)
299/*[clinic end generated code: output=70ac06d25fd3b4da input=c059994022976788]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000300{
301 PANEL *pan;
302 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000304 pan = panel_above(self->pan);
305
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 if (pan == NULL) { /* valid output, it means the calling panel
307 is on top of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200308 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000309 }
310 po = find_po(pan);
311 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 PyErr_SetString(PyExc_RuntimeError,
313 "panel_above: can't find Panel Object");
314 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000315 }
316 Py_INCREF(po);
317 return (PyObject *)po;
318}
319
320/* panel_below(NULL) returns the top panel in the stack. To get
Andrew M. Kuchlingae89af92001-01-19 15:35:26 +0000321 this behaviour we use curses.panel.top_panel(). */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300322/*[clinic input]
323_curses_panel.panel.below
324
325Return the panel below the current panel.
326[clinic start generated code]*/
327
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000328static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300329_curses_panel_panel_below_impl(PyCursesPanelObject *self)
330/*[clinic end generated code: output=282861122e06e3de input=cc08f61936d297c6]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000331{
332 PANEL *pan;
333 PyCursesPanelObject *po;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000335 pan = panel_below(self->pan);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336
337 if (pan == NULL) { /* valid output, it means the calling panel
338 is on the bottom of the stack */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200339 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000340 }
341 po = find_po(pan);
342 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 PyErr_SetString(PyExc_RuntimeError,
344 "panel_below: can't find Panel Object");
345 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000346 }
347 Py_INCREF(po);
348 return (PyObject *)po;
349}
350
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300351/*[clinic input]
352_curses_panel.panel.hidden
353
354Return True if the panel is hidden (not visible), False otherwise.
355[clinic start generated code]*/
356
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000357static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300358_curses_panel_panel_hidden_impl(PyCursesPanelObject *self)
359/*[clinic end generated code: output=66eebd1ab4501a71 input=453d4b4fce25e21a]*/
360{
361 if (panel_hidden(self->pan))
362 Py_RETURN_TRUE;
363 else
364 Py_RETURN_FALSE;
365}
366
367/*[clinic input]
368_curses_panel.panel.move
369
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500370 cls: defining_class
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300371 y: int
372 x: int
373 /
374
375Move the panel to the screen coordinates (y, x).
376[clinic start generated code]*/
377
378static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500379_curses_panel_panel_move_impl(PyCursesPanelObject *self, PyTypeObject *cls,
380 int y, int x)
381/*[clinic end generated code: output=ce546c93e56867da input=60a0e7912ff99849]*/
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300382{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500383 _curses_panel_state *state = PyType_GetModuleState(cls);
384 return PyCursesCheckERR(state, move_panel(self->pan, y, x), "move_panel");
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300385}
386
387/*[clinic input]
388_curses_panel.panel.window
389
390Return the window object associated with the panel.
391[clinic start generated code]*/
392
393static PyObject *
394_curses_panel_panel_window_impl(PyCursesPanelObject *self)
395/*[clinic end generated code: output=5f05940d4106b4cb input=6067353d2c307901]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000396{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000397 Py_INCREF(self->wo);
398 return (PyObject *)self->wo;
399}
400
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300401/*[clinic input]
402_curses_panel.panel.replace
403
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500404 cls: defining_class
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300405 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
406 /
407
408Change the window associated with the panel to the window win.
409[clinic start generated code]*/
410
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000411static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300412_curses_panel_panel_replace_impl(PyCursesPanelObject *self,
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500413 PyTypeObject *cls,
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300414 PyCursesWindowObject *win)
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500415/*[clinic end generated code: output=c71f95c212d58ae7 input=dbec7180ece41ff5]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000416{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500417 _curses_panel_state *state = PyType_GetModuleState(cls);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500419 PyCursesPanelObject *po = find_po(self->pan);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000420 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 PyErr_SetString(PyExc_RuntimeError,
422 "replace_panel: can't find Panel Object");
423 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000424 }
425
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500426 int rtn = replace_panel(self->pan, win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000427 if (rtn == ERR) {
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500428 PyErr_SetString(state->PyCursesError, "replace_panel() returned ERR");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000430 }
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300431 Py_INCREF(win);
432 Py_SETREF(po->wo, win);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200433 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000434}
435
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300436/*[clinic input]
437_curses_panel.panel.set_userptr
438
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500439 cls: defining_class
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300440 obj: object
441 /
442
animalize463572c2019-02-25 07:18:48 +0800443Set the panel's user pointer to obj.
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300444[clinic start generated code]*/
445
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000446static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500447_curses_panel_panel_set_userptr_impl(PyCursesPanelObject *self,
448 PyTypeObject *cls, PyObject *obj)
449/*[clinic end generated code: output=db74f3db07b28080 input=e3fee2ff7b1b8e48]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000450{
Andrew Kuchling53e5ea72013-06-15 14:04:04 -0400451 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000452 Py_INCREF(obj);
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500453 PyObject *oldobj = (PyObject *) panel_userptr(self->pan);
454 int rc = set_panel_userptr(self->pan, (void*)obj);
Andrew Kuchling9290dd12013-06-22 14:50:56 -0400455 if (rc == ERR) {
456 /* In case of an ncurses error, decref the new object again */
457 Py_DECREF(obj);
458 }
459 Py_XDECREF(oldobj);
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500460
461 _curses_panel_state *state = PyType_GetModuleState(cls);
462 return PyCursesCheckERR(state, rc, "set_panel_userptr");
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000463}
464
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300465/*[clinic input]
466_curses_panel.panel.userptr
467
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500468 cls: defining_class
469
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300470Return the user pointer for the panel.
471[clinic start generated code]*/
472
Martin v. Löwisc0e16712002-01-17 23:08:27 +0000473static PyObject *
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500474_curses_panel_panel_userptr_impl(PyCursesPanelObject *self,
475 PyTypeObject *cls)
476/*[clinic end generated code: output=eea6e6f39ffc0179 input=f22ca4f115e30a80]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000477{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500478 _curses_panel_state *state = PyType_GetModuleState(cls);
479
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000480 PyCursesInitialised;
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500481 PyObject *obj = (PyObject *) panel_userptr(self->pan);
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000482 if (obj == NULL) {
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500483 PyErr_SetString(state->PyCursesError, "no userptr set");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000484 return NULL;
Neal Norwitz5e3d8622006-01-09 06:24:35 +0000485 }
486
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000487 Py_INCREF(obj);
488 return obj;
489}
490
491
492/* Module interface */
493
494static PyMethodDef PyCursesPanel_Methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300495 _CURSES_PANEL_PANEL_ABOVE_METHODDEF
496 _CURSES_PANEL_PANEL_BELOW_METHODDEF
497 _CURSES_PANEL_PANEL_BOTTOM_METHODDEF
498 _CURSES_PANEL_PANEL_HIDDEN_METHODDEF
499 _CURSES_PANEL_PANEL_HIDE_METHODDEF
500 _CURSES_PANEL_PANEL_MOVE_METHODDEF
501 _CURSES_PANEL_PANEL_REPLACE_METHODDEF
502 _CURSES_PANEL_PANEL_SET_USERPTR_METHODDEF
503 _CURSES_PANEL_PANEL_SHOW_METHODDEF
504 _CURSES_PANEL_PANEL_TOP_METHODDEF
505 _CURSES_PANEL_PANEL_USERPTR_METHODDEF
506 _CURSES_PANEL_PANEL_WINDOW_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000508};
509
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000510/* -------------------------------------------------------*/
511
Martin v. Löwisbc07cb82012-06-14 16:01:23 +0200512static PyType_Slot PyCursesPanel_Type_slots[] = {
513 {Py_tp_dealloc, PyCursesPanel_Dealloc},
514 {Py_tp_methods, PyCursesPanel_Methods},
515 {0, 0},
516};
517
518static PyType_Spec PyCursesPanel_Type_spec = {
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500519 .name = "_curses_panel.panel",
520 .basicsize = sizeof(PyCursesPanelObject),
521 .flags = Py_TPFLAGS_DEFAULT,
522 .slots = PyCursesPanel_Type_slots
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000523};
524
525/* Wrapper for panel_above(NULL). This function returns the bottom
526 panel of the stack, so it's renamed to bottom_panel().
527 panel.above() *requires* a panel object in the first place which
528 may be undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300529/*[clinic input]
530_curses_panel.bottom_panel
531
532Return the bottom panel in the panel stack.
533[clinic start generated code]*/
534
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000535static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300536_curses_panel_bottom_panel_impl(PyObject *module)
537/*[clinic end generated code: output=3aba9f985f4c2bd0 input=634c2a8078b3d7e4]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000538{
539 PANEL *pan;
540 PyCursesPanelObject *po;
541
542 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000543
544 pan = panel_above(NULL);
545
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000546 if (pan == NULL) { /* valid output, it means
547 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200548 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000549 }
550 po = find_po(pan);
551 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000552 PyErr_SetString(PyExc_RuntimeError,
553 "panel_above: can't find Panel Object");
554 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000555 }
556 Py_INCREF(po);
557 return (PyObject *)po;
558}
559
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300560/*[clinic input]
561_curses_panel.new_panel
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000562
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300563 win: object(type="PyCursesWindowObject *", subclass_of="&PyCursesWindow_Type")
564 /
565
566Return a panel object, associating it with the given window win.
567[clinic start generated code]*/
568
569static PyObject *
570_curses_panel_new_panel_impl(PyObject *module, PyCursesWindowObject *win)
571/*[clinic end generated code: output=45e948e0176a9bd2 input=74d4754e0ebe4800]*/
572{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500573 _curses_panel_state *state = get_curses_panel_state(module);
574
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300575 PANEL *pan = new_panel(win->win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000576 if (pan == NULL) {
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500577 PyErr_SetString(state->PyCursesError, catchall_NULL);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000579 }
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500580 return (PyObject *)PyCursesPanel_New(state, pan, win);
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000581}
582
583
584/* Wrapper for panel_below(NULL). This function returns the top panel
585 of the stack, so it's renamed to top_panel(). panel.below()
586 *requires* a panel object in the first place which may be
587 undesirable. */
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300588/*[clinic input]
589_curses_panel.top_panel
590
591Return the top panel in the panel stack.
592[clinic start generated code]*/
593
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000594static PyObject *
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300595_curses_panel_top_panel_impl(PyObject *module)
596/*[clinic end generated code: output=86704988bea8508e input=e62d6278dba39e79]*/
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000597{
598 PANEL *pan;
599 PyCursesPanelObject *po;
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
603 pan = panel_below(NULL);
604
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000605 if (pan == NULL) { /* valid output, it means
606 there's no panel at all */
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200607 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000608 }
609 po = find_po(pan);
610 if (po == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 PyErr_SetString(PyExc_RuntimeError,
612 "panel_below: can't find Panel Object");
613 return NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000614 }
615 Py_INCREF(po);
616 return (PyObject *)po;
617}
618
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300619/*[clinic input]
620_curses_panel.update_panels
621
622Updates the virtual screen after changes in the panel stack.
623
animalize463572c2019-02-25 07:18:48 +0800624This does not call curses.doupdate(), so you'll have to do this yourself.
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300625[clinic start generated code]*/
626
627static PyObject *
628_curses_panel_update_panels_impl(PyObject *module)
animalize463572c2019-02-25 07:18:48 +0800629/*[clinic end generated code: output=2f3b4c2e03d90ded input=5299624c9a708621]*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000630{
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000631 PyCursesInitialised;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000632 update_panels();
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200633 Py_RETURN_NONE;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000634}
635
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000636/* List of functions defined in the module */
637
638static PyMethodDef PyCurses_methods[] = {
Serhiy Storchakab00854c2018-05-10 11:27:23 +0300639 _CURSES_PANEL_BOTTOM_PANEL_METHODDEF
640 _CURSES_PANEL_NEW_PANEL_METHODDEF
641 _CURSES_PANEL_TOP_PANEL_METHODDEF
642 _CURSES_PANEL_UPDATE_PANELS_METHODDEF
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000643 {NULL, NULL} /* sentinel */
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000644};
645
646/* Initialization function for the module */
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500647static int
648_curses_panel_exec(PyObject *mod)
649{
650 _curses_panel_state *state = get_curses_panel_state(mod);
651 /* Initialize object type */
652 state->PyCursesPanel_Type = (PyTypeObject *)PyType_FromModuleAndSpec(
653 mod, &PyCursesPanel_Type_spec, NULL);
654 if (state->PyCursesPanel_Type == NULL) {
655 return -1;
656 }
Victor Stinner993e88c2020-12-26 02:17:46 +0100657 ((PyTypeObject *)state->PyCursesPanel_Type)->tp_new = NULL;
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000658
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500659 if (PyModule_AddType(mod, state->PyCursesPanel_Type) < 0) {
660 return -1;
661 }
662
663 import_curses();
664 if (PyErr_Occurred()) {
665 return -1;
666 }
667
668 /* For exception _curses_panel.error */
669 state->PyCursesError = PyErr_NewException(
670 "_curses_panel.error", NULL, NULL);
671
672 Py_INCREF(state->PyCursesError);
673 if (PyModule_AddObject(mod, "error", state->PyCursesError) < 0) {
674 Py_DECREF(state->PyCursesError);
675 return -1;
676 }
677
678 /* Make the version available */
679 PyObject *v = PyUnicode_FromString(PyCursesVersion);
680 if (v == NULL) {
681 return -1;
682 }
683
684 PyObject *d = PyModule_GetDict(mod);
685 if (PyDict_SetItemString(d, "version", v) < 0) {
686 Py_DECREF(v);
687 return -1;
688 }
689 if (PyDict_SetItemString(d, "__version__", v) < 0) {
690 Py_DECREF(v);
691 return -1;
692 }
693
694 Py_DECREF(v);
695
696 return 0;
697}
698
699static PyModuleDef_Slot _curses_slots[] = {
700 {Py_mod_exec, _curses_panel_exec},
701 {0, NULL}
702};
Martin v. Löwis1a214512008-06-11 05:26:20 +0000703
704static struct PyModuleDef _curses_panelmodule = {
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500705 PyModuleDef_HEAD_INIT,
706 .m_name = "_curses_panel",
707 .m_size = sizeof(_curses_panel_state),
708 .m_methods = PyCurses_methods,
709 .m_slots = _curses_slots,
710 .m_traverse = _curses_panel_traverse,
711 .m_clear = _curses_panel_clear,
712 .m_free = _curses_panel_free
Martin v. Löwis1a214512008-06-11 05:26:20 +0000713};
714
Mark Hammondfe51c6d2002-08-02 02:27:13 +0000715PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000716PyInit__curses_panel(void)
Andrew M. Kuchling7b59ed22000-12-22 21:54:12 +0000717{
Mohamed Koubaa1baf0302020-09-07 10:14:25 -0500718 return PyModuleDef_Init(&_curses_panelmodule);
Victor Stinner993e88c2020-12-26 02:17:46 +0100719}