2 * Interface to the ncurses panel library
4 * Original version by Thomas Gellekum
9 static char *PyCursesVersion
= "2.1";
15 #include "py_curses.h"
19 static PyObject
*PyCursesError
;
22 /* Utility Functions */
25 * Check the return code from a curses function and return None
26 * or raise an exception as appropriate.
30 PyCursesCheckERR(int code
, char *fname
)
37 PyErr_SetString(PyCursesError
, catchall_ERR
);
39 PyErr_Format(PyCursesError
, "%s() returned ERR", fname
);
45 /*****************************************************************************
47 ******************************************************************************/
49 /* Definition of the panel object and panel type */
54 PyCursesWindowObject
*wo
; /* for reference counts */
55 } PyCursesPanelObject
;
57 PyTypeObject PyCursesPanel_Type
;
59 #define PyCursesPanel_Check(v) ((v)->ob_type == &PyCursesPanel_Type)
61 /* Some helper functions. The problem is that there's always a window
62 associated with a panel. To ensure that Python's GC doesn't pull
63 this window from under our feet we need to keep track of references
64 to the corresponding window object within Python. We can't use
65 dupwin(oldwin) to keep a copy of the curses WINDOW because the
66 contents of oldwin is copied only once; code like
70 win.addstr(some_string)
71 pan.window().addstr(other_string)
75 /* We keep a linked list of PyCursesPanelObjects, lop. A list should
76 suffice, I don't expect more than a handful or at most a few
77 dozens of panel objects within a typical program. */
78 typedef struct _list_of_panels
{
79 PyCursesPanelObject
*po
;
80 struct _list_of_panels
*next
;
84 static list_of_panels
*lop
;
86 /* Insert a new panel object into lop */
88 insert_lop(PyCursesPanelObject
*po
)
92 if ((new = (list_of_panels
*)malloc(sizeof(list_of_panels
))) == NULL
) {
102 /* Remove the panel object from lop */
104 remove_lop(PyCursesPanelObject
*po
)
106 list_of_panels
*temp
, *n
;
109 if (temp
->po
== po
) {
114 while (temp
->next
->po
!= po
) {
115 if (temp
->next
== NULL
)
116 PyErr_SetString(PyExc_RuntimeError
,
117 "remove_lop: can't find Panel Object");
120 n
= temp
->next
->next
;
126 /* Return the panel object that corresponds to pan */
127 static PyCursesPanelObject
*
130 list_of_panels
*temp
;
131 for (temp
= lop
; temp
->po
->pan
!= pan
; temp
= temp
->next
)
132 if (temp
->next
== NULL
) return NULL
; /* not found!? */
136 /* Function Prototype Macros - They are ugly but very, very useful. ;-)
139 TYPE - parameter Type
140 ERGSTR - format string for construction of the return value
141 PARSESTR - format string for argument parsing */
143 #define Panel_NoArgNoReturnFunction(X) \
144 static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self, PyObject *args) \
145 { if (!PyArg_NoArgs(args)) return NULL; \
146 return PyCursesCheckERR(X(self->pan), # X); }
148 #define Panel_NoArgTrueFalseFunction(X) \
149 static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self, PyObject *args) \
151 if (!PyArg_NoArgs(args)) return NULL; \
152 if (X (self->pan) == FALSE) { Py_INCREF(Py_False); return Py_False; } \
153 else { Py_INCREF(Py_True); return Py_True; } }
155 #define Panel_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \
156 static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self, PyObject *args) \
159 if (!PyArg_Parse(args,PARSESTR, &arg1, &arg2)) return NULL; \
160 return PyCursesCheckERR(X(self->pan, arg1, arg2), # X); }
162 /* ------------- PANEL routines --------------- */
164 Panel_NoArgNoReturnFunction(bottom_panel
)
165 Panel_NoArgNoReturnFunction(hide_panel
)
166 Panel_NoArgNoReturnFunction(show_panel
)
167 Panel_NoArgNoReturnFunction(top_panel
)
168 Panel_NoArgTrueFalseFunction(panel_hidden
)
169 Panel_TwoArgNoReturnFunction(move_panel
, int, "(ii);y,x")
171 /* Allocation and deallocation of Panel Objects */
174 PyCursesPanel_New(PANEL
*pan
, PyCursesWindowObject
*wo
)
176 PyCursesPanelObject
*po
;
178 po
= PyObject_NEW(PyCursesPanelObject
, &PyCursesPanel_Type
);
179 if (po
== NULL
) return NULL
;
183 if (insert_lop(po
) < 0) {
187 return (PyObject
*)po
;
191 PyCursesPanel_Dealloc(PyCursesPanelObject
*po
)
193 (void)del_panel(po
->pan
);
199 /* panel_above(NULL) returns the bottom panel in the stack. To get
200 this behaviour we use curses.panel.bottom_panel(). */
202 PyCursesPanel_above(PyCursesPanelObject
*self
, PyObject
*args
)
205 PyCursesPanelObject
*po
;
207 if (!PyArg_NoArgs(args
)) return NULL
;
209 pan
= panel_above(self
->pan
);
211 if (pan
== NULL
) { /* valid output, it means the calling panel
212 is on top of the stack */
218 PyErr_SetString(PyExc_RuntimeError
,
219 "panel_above: can't find Panel Object");
223 return (PyObject
*)po
;
226 /* panel_below(NULL) returns the top panel in the stack. To get
227 this behaviour we use curses.panel.top_panel(). */
229 PyCursesPanel_below(PyCursesPanelObject
*self
, PyObject
*args
)
232 PyCursesPanelObject
*po
;
234 if (!PyArg_NoArgs(args
)) return NULL
;
236 pan
= panel_below(self
->pan
);
238 if (pan
== NULL
) { /* valid output, it means the calling panel
239 is on the bottom of the stack */
245 PyErr_SetString(PyExc_RuntimeError
,
246 "panel_below: can't find Panel Object");
250 return (PyObject
*)po
;
254 PyCursesPanel_window(PyCursesPanelObject
*self
, PyObject
*args
)
256 if (!PyArg_NoArgs(args
)) return NULL
;
259 return (PyObject
*)self
->wo
;
263 PyCursesPanel_replace_panel(PyCursesPanelObject
*self
, PyObject
*args
)
265 PyCursesPanelObject
*po
;
266 PyCursesWindowObject
*temp
;
269 if (ARG_COUNT(args
) != 1) {
270 PyErr_SetString(PyExc_TypeError
, "replace requires one argument");
273 if (!PyArg_ParseTuple(args
, "O!;window object",
274 &PyCursesWindow_Type
, &temp
))
277 po
= find_po(self
->pan
);
279 PyErr_SetString(PyExc_RuntimeError
,
280 "replace_panel: can't find Panel Object");
284 rtn
= replace_panel(self
->pan
, temp
->win
);
286 PyErr_SetString(PyCursesError
, "replace_panel() returned ERR");
297 PyCursesPanel_set_panel_userptr(PyCursesPanelObject
*self
, PyObject
*args
)
301 if (ARG_COUNT(args
) != 1) {
302 PyErr_SetString(PyExc_TypeError
, "set_userptr requires one argument");
305 obj
= PyTuple_GetItem(args
, 0);
307 return PyCursesCheckERR(set_panel_userptr(self
->pan
, obj
),
308 "set_panel_userptr");
311 static PyObject
*PyCursesPanel_userptr
312 (PyCursesPanelObject
*self
, PyObject
*args
)
316 if (!PyArg_NoArgs(args
))
318 obj
= (PyObject
*) panel_userptr(self
->pan
);
324 /* Module interface */
326 static PyMethodDef PyCursesPanel_Methods
[] = {
327 {"above", (PyCFunction
)PyCursesPanel_above
},
328 {"below", (PyCFunction
)PyCursesPanel_below
},
329 {"bottom", (PyCFunction
)PyCursesPanel_bottom_panel
},
330 {"hidden", (PyCFunction
)PyCursesPanel_panel_hidden
},
331 {"hide", (PyCFunction
)PyCursesPanel_hide_panel
},
332 {"move", (PyCFunction
)PyCursesPanel_move_panel
},
333 {"replace", (PyCFunction
)PyCursesPanel_replace_panel
,
335 {"set_userptr", (PyCFunction
)PyCursesPanel_set_panel_userptr
,
337 {"show", (PyCFunction
)PyCursesPanel_show_panel
},
338 {"top", (PyCFunction
)PyCursesPanel_top_panel
},
339 {"userptr", (PyCFunction
)PyCursesPanel_userptr
},
340 {"window", (PyCFunction
)PyCursesPanel_window
},
341 {NULL
, NULL
} /* sentinel */
345 PyCursesPanel_GetAttr(PyCursesPanelObject
*self
, char *name
)
347 return Py_FindMethod(PyCursesPanel_Methods
, (PyObject
*)self
, name
);
350 /* -------------------------------------------------------*/
352 PyTypeObject PyCursesPanel_Type
= {
353 PyObject_HEAD_INIT(NULL
)
355 "curses panel", /*tp_name*/
356 sizeof(PyCursesPanelObject
), /*tp_basicsize*/
359 (destructor
)PyCursesPanel_Dealloc
, /*tp_dealloc*/
361 (getattrfunc
)PyCursesPanel_GetAttr
, /*tp_getattr*/
362 (setattrfunc
)0, /*tp_setattr*/
366 0, /*tp_as_sequence*/
371 /* Wrapper for panel_above(NULL). This function returns the bottom
372 panel of the stack, so it's renamed to bottom_panel().
373 panel.above() *requires* a panel object in the first place which
374 may be undesirable. */
376 PyCurses_bottom_panel(PyObject
*self
, PyObject
*args
)
379 PyCursesPanelObject
*po
;
383 if (!PyArg_NoArgs(args
)) return NULL
;
385 pan
= panel_above(NULL
);
387 if (pan
== NULL
) { /* valid output, it means
388 there's no panel at all */
394 PyErr_SetString(PyExc_RuntimeError
,
395 "panel_above: can't find Panel Object");
399 return (PyObject
*)po
;
403 PyCurses_new_panel(PyObject
*self
, PyObject
*args
)
405 PyCursesWindowObject
*win
;
408 if (!PyArg_ParseTuple(args
, "O!", &PyCursesWindow_Type
, &win
))
410 pan
= new_panel(win
->win
);
412 PyErr_SetString(PyCursesError
, catchall_NULL
);
415 return (PyObject
*)PyCursesPanel_New(pan
, win
);
419 /* Wrapper for panel_below(NULL). This function returns the top panel
420 of the stack, so it's renamed to top_panel(). panel.below()
421 *requires* a panel object in the first place which may be
424 PyCurses_top_panel(PyObject
*self
, PyObject
*args
)
427 PyCursesPanelObject
*po
;
431 if (!PyArg_NoArgs(args
)) return NULL
;
433 pan
= panel_below(NULL
);
435 if (pan
== NULL
) { /* valid output, it means
436 there's no panel at all */
442 PyErr_SetString(PyExc_RuntimeError
,
443 "panel_below: can't find Panel Object");
447 return (PyObject
*)po
;
450 static PyObject
*PyCurses_update_panels(PyObject
*self
, PyObject
*args
)
453 if (!PyArg_NoArgs(args
)) return NULL
;
460 /* List of functions defined in the module */
462 static PyMethodDef PyCurses_methods
[] = {
463 {"bottom_panel", (PyCFunction
)PyCurses_bottom_panel
},
464 {"new_panel", (PyCFunction
)PyCurses_new_panel
, METH_VARARGS
},
465 {"top_panel", (PyCFunction
)PyCurses_top_panel
},
466 {"update_panels", (PyCFunction
)PyCurses_update_panels
},
467 {NULL
, NULL
} /* sentinel */
470 /* Initialization function for the module */
473 init_curses_panel(void)
477 /* Initialize object type */
478 PyCursesPanel_Type
.ob_type
= &PyType_Type
;
482 /* Create the module and add the functions */
483 m
= Py_InitModule("_curses_panel", PyCurses_methods
);
484 d
= PyModule_GetDict(m
);
486 /* For exception _curses_panel.error */
487 PyCursesError
= PyErr_NewException("_curses_panel.error", NULL
, NULL
);
488 PyDict_SetItemString(d
, "error", PyCursesError
);
490 /* Make the version available */
491 v
= PyString_FromString(PyCursesVersion
);
492 PyDict_SetItemString(d
, "version", v
);
493 PyDict_SetItemString(d
, "__version__", v
);