# The current screen is unchanged, so refreshing it still works.
screen.stdscr.refresh()
+ @unittest.skipUnless(hasattr(curses, 'new_prescr'),
+ 'requires curses.new_prescr()')
+ @unittest.skipUnless(hasattr(curses.screen, 'use'),
+ 'requires curses.screen.use()')
+ def test_use_prescr_screen(self):
+ # use() makes its screen current for the callback, so a new_prescr()
+ # screen is current there without having a terminal. Operations that
+ # need one used to crash inside curses.
+ s = self.make_pty()
+ screen = curses.newterm('xterm', s, s)
+ prescr = curses.new_prescr()
+ for func in [
+ lambda scr: curses.doupdate(),
+ lambda scr: curses.newwin(3, 3),
+ lambda scr: screen.stdscr.refresh(),
+ lambda scr: screen.stdscr.getch(),
+ ]:
+ with self.assertRaises(curses.error):
+ prescr.use(func)
+ # Affecting the state before initscr() is what such a screen is for.
+ prescr.use(lambda scr: curses.use_env(False))
+ # The current screen is unchanged.
+ screen.stdscr.refresh()
+
def test_initscr_after_newterm_keeps_screen_alive(self):
# initscr() called while a newterm() screen is current returns that
# screen's own standard window, so the window keeps the screen alive.
return 0;
}
+/*
+ * Function to check that the current screen has a terminal, by testing
+ * stdscr, which a screen made by new_prescr() does not have. If an error
+ * occurs, a PyCursesError is set and this returns 0. Otherwise this
+ * returns 1.
+ */
+static int
+_PyCursesStatefulCheckTerminal(PyObject *module)
+{
+ if (stdscr != NULL) {
+ return 1;
+ }
+ cursesmodule_state *state = get_cursesmodule_state(module);
+ PyErr_SetString(state->error, "the current screen has no terminal");
+ return 0;
+}
+
+/* Same as _PyCursesStatefulCheckTerminal() for a Window object. */
+static int
+curses_window_check_terminal(PyCursesWindowObject *win)
+{
+ if (stdscr != NULL) {
+ return 1;
+ }
+ cursesmodule_state *state = get_cursesmodule_state_by_win(win);
+ PyErr_SetString(state->error, "the current screen has no terminal");
+ return 0;
+}
+
#define PyCursesStatefulSetupTermCalled(MODULE) \
do { \
if (!_PyCursesStatefulCheckFunction(MODULE, \
do { \
if (!_PyCursesStatefulCheckFunction(MODULE, \
curses_initscr_called, \
- "initscr")) \
+ "initscr") \
+ || !_PyCursesStatefulCheckTerminal(MODULE)) \
{ \
return 0; \
} \
Py_RETURN_NONE; \
}
+/* Same as Window_OneArgNoReturnVoidFunction() for a function that needs
+ a terminal. */
+#define Window_OneArgNoReturnVoidTerminalFunction(X, TYPE, PARSESTR) \
+ static PyObject * PyCursesWindow_ ## X \
+ (PyObject *op, PyObject *args) \
+ { \
+ TYPE arg1; \
+ if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) { \
+ return NULL; \
+ } \
+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \
+ if (!curses_window_check_terminal(self)) { \
+ return NULL; \
+ } \
+ X(self->win, arg1); \
+ Py_RETURN_NONE; \
+ }
+
+/* Same as Window_OneArgNoReturnFunction() for a function that needs
+ a terminal. */
+#define Window_OneArgNoReturnTerminalFunction(X, TYPE, PARSESTR) \
+ static PyObject * PyCursesWindow_ ## X \
+ (PyObject *op, PyObject *args) \
+ { \
+ TYPE arg1; \
+ if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) { \
+ return NULL; \
+ } \
+ PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op); \
+ if (!curses_window_check_terminal(self)) { \
+ return NULL; \
+ } \
+ int code = X(self->win, arg1); \
+ return curses_window_check_err(self, code, # X, NULL); \
+ }
+
#define Window_OneArgNoReturnFunction(X, TYPE, PARSESTR) \
static PyObject * PyCursesWindow_ ## X \
(PyObject *op, PyObject *args) \
Window_NoArgNoReturnVoidFunction(wclrtobot)
Window_NoArgNoReturnVoidFunction(wclear)
-Window_OneArgNoReturnVoidFunction(idcok, int, "i;True(1) or False(0)")
+Window_OneArgNoReturnVoidTerminalFunction(idcok, int, "i;True(1) or False(0)")
#ifdef HAVE_CURSES_IMMEDOK
Window_OneArgNoReturnVoidFunction(immedok, int, "i;True(1) or False(0)")
#endif
Window_NoArg2TupleReturnFunction(getparyx, int, "ii")
Window_OneArgNoReturnFunction(clearok, int, "i;True(1) or False(0)")
-Window_OneArgNoReturnFunction(idlok, int, "i;True(1) or False(0)")
-Window_OneArgNoReturnFunction(keypad, int, "i;True(1) or False(0)")
+Window_OneArgNoReturnTerminalFunction(idlok, int, "i;True(1) or False(0)")
+Window_OneArgNoReturnTerminalFunction(keypad, int, "i;True(1) or False(0)")
Window_OneArgNoReturnFunction(leaveok, int, "i;True(1) or False(0)")
Window_OneArgNoReturnFunction(nodelay, int, "i;True(1) or False(0)")
Window_OneArgNoReturnFunction(notimeout, int, "i;True(1) or False(0)")
int group_right_1, attr_t attr)
/*[clinic end generated code: output=ab03afa580aa6a2a input=cd74c42aadcc7e30]*/
{
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
+
chtype ch_;
#ifdef HAVE_NCURSESW
cchar_t wch;
{
int rtn;
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
if (!group_right_1) {
rtn = wgetch(self->win);
{
int rtn;
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
if (!group_right_1) {
rtn = wgetch(self->win);
int y, int x)
/*[clinic end generated code: output=9f4f86e91fe50ef3 input=dd7e5367fb49dc48]*/
{
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
+
#ifdef HAVE_NCURSESW
int ct;
wint_t rtn;
PyCursesWindow_getstr(PyObject *op, PyObject *args)
{
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
+
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
return curses_window_getstr_bytes(self, args, "_curses.window.getstr");
}
PyCursesWindow_get_wstr(PyObject *op, PyObject *args)
{
PyCursesWindowObject *self = _PyCursesWindowObject_CAST(op);
+
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
#ifdef HAVE_NCURSESW
int rtn, use_xy = 0, y = 0, x = 0;
unsigned int max_buf_size = 2048;
{
int rtn;
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
+
#ifdef py_is_pad
if (py_is_pad(self->win)) {
if (!group_right_1) {
{
int rtn;
+ if (!curses_window_check_terminal(self)) {
+ return NULL;
+ }
+
#ifdef py_is_pad
if (py_is_pad(self->win)) {
if (!group_right_1) {