diff options
author | Andrew M. Kuchling <amk@amk.ca> | 2000-12-22 21:54:12 (GMT) |
---|---|---|
committer | Andrew M. Kuchling <amk@amk.ca> | 2000-12-22 21:54:12 (GMT) |
commit | 7b59ed2ebdeff477c1cac90a00cf5769a43c62f5 (patch) | |
tree | 508e3ec11dbc613fbc27517ba059302d0009da9f /Modules | |
parent | 325526877710cb4010e2ba5d6eb67cac0265911e (diff) | |
download | cpython-7b59ed2ebdeff477c1cac90a00cf5769a43c62f5.zip cpython-7b59ed2ebdeff477c1cac90a00cf5769a43c62f5.tar.gz cpython-7b59ed2ebdeff477c1cac90a00cf5769a43c62f5.tar.bz2 |
Patch #102813: add a wrapper for the panel library included with ncurses.
Original version written by Thomas Gellekum, reshaped into a separate
module by AMK.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_curses_panel.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c new file mode 100644 index 0000000..313f83e --- /dev/null +++ b/Modules/_curses_panel.c @@ -0,0 +1,495 @@ +/* + * Interface to the ncurses panel library + * + * Original version by Thomas Gellekum + */ + +/* Release Number */ + +static char *PyCursesVersion = "2.1"; + +/* Includes */ + +#include "Python.h" + +#include "py_curses.h" + +#include <panel.h> + +static PyObject *PyCursesError; + + +/* Utility Functions */ + +/* + * Check the return code from a curses function and return None + * or raise an exception as appropriate. + */ + +static PyObject * +PyCursesCheckERR(int code, char *fname) +{ + if (code != ERR) { + Py_INCREF(Py_None); + return Py_None; + } else { + if (fname == NULL) { + PyErr_SetString(PyCursesError, catchall_ERR); + } else { + PyErr_Format(PyCursesError, "%s() returned ERR", fname); + } + return NULL; + } +} + +/***************************************************************************** + The Panel Object +******************************************************************************/ + +/* Definition of the panel object and panel type */ + +typedef struct { + PyObject_HEAD + PANEL *pan; + PyCursesWindowObject *wo; /* for reference counts */ +} PyCursesPanelObject; + +PyTypeObject PyCursesPanel_Type; + +#define PyCursesPanel_Check(v) ((v)->ob_type == &PyCursesPanel_Type) + +/* Some helper functions. The problem is that there's always a window + associated with a panel. To ensure that Python's GC doesn't pull + this window from under our feet we need to keep track of references + to the corresponding window object within Python. We can't use + dupwin(oldwin) to keep a copy of the curses WINDOW because the + contents of oldwin is copied only once; code like + + win = newwin(...) + pan = win.panel() + win.addstr(some_string) + pan.window().addstr(other_string) + + will fail. */ + +/* We keep a linked list of PyCursesPanelObjects, lop. A list should + suffice, I don't expect more than a handful or at most a few + dozens of panel objects within a typical program. */ +typedef struct _list_of_panels { + PyCursesPanelObject *po; + struct _list_of_panels *next; +} list_of_panels; + +/* list anchor */ +static list_of_panels *lop; + +/* Insert a new panel object into lop */ +static int +insert_lop(PyCursesPanelObject *po) +{ + list_of_panels *new; + + if ((new = (list_of_panels *)malloc(sizeof(list_of_panels))) == NULL) { + PyErr_NoMemory(); + return -1; + } + new->po = po; + new->next = lop; + lop = new; + return 0; +} + +/* Remove the panel object from lop */ +static void +remove_lop(PyCursesPanelObject *po) +{ + list_of_panels *temp, *n; + + temp = lop; + if (temp->po == po) { + lop = temp->next; + free(temp); + return; + } + while (temp->next->po != po) { + if (temp->next == NULL) + PyErr_SetString(PyExc_RuntimeError, + "remove_lop: can't find Panel Object"); + temp = temp->next; + } + n = temp->next->next; + free(temp->next); + temp->next = n; + return; +} + +/* Return the panel object that corresponds to pan */ +static PyCursesPanelObject * +find_po(PANEL *pan) +{ + list_of_panels *temp; + for (temp = lop; temp->po->pan != pan; temp = temp->next) + if (temp->next == NULL) return NULL; /* not found!? */ + return temp->po; +} + +/* Function Prototype Macros - They are ugly but very, very useful. ;-) + + X - function name + TYPE - parameter Type + ERGSTR - format string for construction of the return value + PARSESTR - format string for argument parsing */ + +#define Panel_NoArgNoReturnFunction(X) \ +static PyObject *PyCursesPanel_ ## X (PyCursesPanelObject *self, PyObject *args) \ +{ if (!PyArg_NoArgs(args)) return NULL; \ + return PyCursesCheckERR(X(self->pan), # X); } + +#define Panel_NoArgReturnStringFunction(X) \ +static PyObject *PyCursesPanel_ ## X (PyCursesPanelObject *self, PyObject *args) \ +{ if (!PyArg_NoArgs(args)) return NULL; \ + return PyString_FromString(X(self->pan)); } + +#define Panel_NoArgTrueFalseFunction(X) \ +static PyObject * PyCursesPanel_ ## X (PyCursesPanelObject *self, PyObject *args) \ +{ \ + if (!PyArg_NoArgs(args)) return NULL; \ + if (X (self->pan) == FALSE) { Py_INCREF(Py_False); return Py_False; } \ + else { Py_INCREF(Py_True); return Py_True; } } + +#define Panel_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ +static PyObject * PyCursesPanel_ ## X (PyCursesPanelObject *self, PyObject *args) \ +{ \ + TYPE arg1, arg2; \ + if (!PyArg_Parse(args,PARSESTR, &arg1, &arg2)) return NULL; \ + return PyCursesCheckERR(X(self->pan, arg1, arg2), # X); } + +/* ------------- PANEL routines --------------- */ + +Panel_NoArgNoReturnFunction(bottom_panel) +Panel_NoArgNoReturnFunction(hide_panel) +Panel_NoArgNoReturnFunction(show_panel) +Panel_NoArgNoReturnFunction(top_panel) +Panel_NoArgTrueFalseFunction(panel_hidden) +Panel_TwoArgNoReturnFunction(move_panel, int, "(ii);y,x") + +/* Allocation and deallocation of Panel Objects */ + +static PyObject * +PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo) +{ + PyCursesPanelObject *po; + + po = PyObject_NEW(PyCursesPanelObject, &PyCursesPanel_Type); + if (po == NULL) return NULL; + po->pan = pan; + po->wo = wo; + Py_INCREF(wo); + if (insert_lop(po) < 0) { + PyObject_DEL(po); + return NULL; + } + return (PyObject *)po; +} + +static void +PyCursesPanel_Dealloc(PyCursesPanelObject *po) +{ + (void)del_panel(po->pan); + Py_DECREF(po->wo); + remove_lop(po); + PyMem_DEL(po); +} + +/* panel_above(NULL) returns the bottom panel in the stack. To get + this behaviour we use curses.panel.bottom_panel(). */ +static PyObject * +PyCursesPanel_above(PyCursesPanelObject *self, PyObject *args) +{ + PANEL *pan; + PyCursesPanelObject *po; + + if (!PyArg_NoArgs(args)) return NULL; + + pan = panel_above(self->pan); + + if (pan == NULL) { /* valid output, it means the calling panel + is on top of the stack */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_above: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +/* panel_below(NULL) returns the top panel in the stack. To get + this behaviour we use curses.panel_below(). */ +static PyObject * +PyCursesPanel_below(PyCursesPanelObject *self, PyObject *args) +{ + PANEL *pan; + PyCursesPanelObject *po; + + if (!PyArg_NoArgs(args)) return NULL; + + pan = panel_below(self->pan); + + if (pan == NULL) { /* valid output, it means the calling panel + is on the bottom of the stack */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_below: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +static PyObject * +PyCursesPanel_window(PyCursesPanelObject *self, PyObject *args) +{ + if (!PyArg_NoArgs(args)) return NULL; + + Py_INCREF(self->wo); + return (PyObject *)self->wo; +} + +static PyObject * +PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args) +{ + PyCursesPanelObject *po; + PyCursesWindowObject *temp; + int rtn; + + if (ARG_COUNT(args) != 1) { + PyErr_SetString(PyExc_TypeError, "replace requires one argument"); + return NULL; + } + if (!PyArg_ParseTuple(args, "O!;window object", + &PyCursesWindow_Type, &temp)) + return NULL; + + po = find_po(self->pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "replace_panel: can't find Panel Object"); + return NULL; + } + + rtn = replace_panel(self->pan, temp->win); + if (rtn == ERR) { + PyErr_SetString(PyCursesError, "replace_panel() returned ERR"); + return NULL; + } + Py_DECREF(po->wo); + po->wo = temp; + Py_INCREF(po->wo); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyCursesPanel_set_panel_userptr(PyCursesPanelObject *self, PyObject *args) +{ + PyObject *obj; + + if (ARG_COUNT(args) != 1) { + PyErr_SetString(PyExc_TypeError, "set_userptr requires one argument"); + return NULL; + } + obj = PyTuple_GetItem(args, 0); + Py_INCREF(obj); + return PyCursesCheckERR(set_panel_userptr(self->pan, obj), "set_panel_userptr"); +} + +static PyObject *PyCursesPanel_userptr +(PyCursesPanelObject *self, PyObject *args) +{ + PyObject *obj; + PyCursesInitialised; + if (!PyArg_NoArgs(args)) return NULL; + obj = panel_userptr(self->pan); + Py_INCREF(obj); + return obj; +} + + +/* Module interface */ + +static PyMethodDef PyCursesPanel_Methods[] = { + {"above", (PyCFunction)PyCursesPanel_above}, + {"below", (PyCFunction)PyCursesPanel_below}, + {"bottom", (PyCFunction)PyCursesPanel_bottom_panel}, + {"hidden", (PyCFunction)PyCursesPanel_panel_hidden}, + {"hide", (PyCFunction)PyCursesPanel_hide_panel}, + {"move", (PyCFunction)PyCursesPanel_move_panel}, + {"replace", (PyCFunction)PyCursesPanel_replace_panel}, + {"set_userptr", (PyCFunction)PyCursesPanel_set_panel_userptr, + METH_VARARGS}, + {"show", (PyCFunction)PyCursesPanel_show_panel}, + {"top", (PyCFunction)PyCursesPanel_top_panel}, + {"userptr", (PyCFunction)PyCursesPanel_userptr}, + {"window", (PyCFunction)PyCursesPanel_window}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +PyCursesPanel_GetAttr(PyCursesPanelObject *self, char *name) +{ + return Py_FindMethod(PyCursesPanel_Methods, (PyObject *)self, name); +} + +/* -------------------------------------------------------*/ + +PyTypeObject PyCursesPanel_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "curses panel", /*tp_name*/ + sizeof(PyCursesPanelObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyCursesPanel_Dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)PyCursesPanel_GetAttr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +/* Wrapper for panel_above(NULL). This function returns the bottom + panel of the stack, so it's renamed to bottom_panel(). + panel.above() *requires* a panel object in the first place which + may be undesirable. */ +static PyObject * +PyCurses_bottom_panel(PyObject *self, PyObject *args) +{ + PANEL *pan; + PyCursesPanelObject *po; + + PyCursesInitialised; + + if (!PyArg_NoArgs(args)) return NULL; + + pan = panel_above(NULL); + + if (pan == NULL) { /* valid output, it means there's no panel at + all */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_above: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +static PyObject * +PyCurses_new_panel(PyObject *self, PyObject *args) +{ + PyCursesWindowObject *win; + PANEL *pan; + + if (!PyArg_ParseTuple(args, "O!", &PyCursesWindow_Type, &win)) return NULL; + pan = new_panel(win->win); + if (pan == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + return (PyObject *)PyCursesPanel_New(pan, win); +} + + +/* Wrapper for panel_below(NULL). This function returns the top panel + of the stack, so it's renamed to top_panel(). panel.below() + *requires* a panel object in the first place which may be + undesirable. */ +static PyObject * +PyCurses_top_panel(PyObject *self, PyObject *args) +{ + PANEL *pan; + PyCursesPanelObject *po; + + PyCursesInitialised; + + if (!PyArg_NoArgs(args)) return NULL; + + pan = panel_below(NULL); + + if (pan == NULL) { /* valid output, it means + there's no panel at all */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_below: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +static PyObject *PyCurses_update_panels(PyObject *self, PyObject *args) +{ + PyCursesInitialised; + if (!PyArg_NoArgs(args)) return NULL; + update_panels(); + Py_INCREF(Py_None); + return Py_None; +} + + +/* List of functions defined in the module */ + +static PyMethodDef PyCurses_methods[] = { + {"bottom_panel", (PyCFunction)PyCurses_bottom_panel}, + {"new_panel", (PyCFunction)PyCurses_new_panel, METH_VARARGS}, + {"top_panel", (PyCFunction)PyCurses_top_panel}, + {"update_panels", (PyCFunction)PyCurses_update_panels}, + {NULL, NULL} /* sentinel */ +}; + +/* Initialization function for the module */ + +void +init_curses_panel(void) +{ + PyObject *m, *d, *v; + + import_curses(); + + /* Create the module and add the functions */ + m = Py_InitModule("_curses_panel", PyCurses_methods); + d = PyModule_GetDict(m); + + /* For exception _curses_panel.error */ + PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL); + PyDict_SetItemString(d, "error", PyCursesError); + + /* Make the version available */ + v = PyString_FromString(PyCursesVersion); + PyDict_SetItemString(d, "version", v); + PyDict_SetItemString(d, "__version__", v); + Py_DECREF(v); + +} + |