Add the immutable `curses.complexchar` type: a styled wide-character cell — a spacing character optionally followed by combining characters, plus attributes and a color pair. The color pair is stored separately rather than packed into a `chtype` via `COLOR_PAIR()`, so it is not limited to the values that fit alongside the attribute bits. `str(cc)` returns the text; the read-only `attr` and `pair` attributes return its rendition.
Add the window methods `in_wch()` and `getbkgrnd()` — the wide-character counterparts of `inch()` and `getbkgd()` — which return a `complexchar`. (`inch()`/`getbkgd()` can only return a packed `chtype`, so these fill a real gap; this resolves the long-standing gh-83395 request for `in_wch`.)
The existing character-cell methods (`addch`, `insch`, `echochar`, `bkgd`, `bkgdset`, `border`, `box`, `hline`, `vline`) now also accept a `complexchar`. A `complexchar` already carries its own rendition, so passing one together with an explicit `attr` argument raises `TypeError`.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
.. versionchanged:: next
A character may now be given as a string of a base character followed
- by combining characters, instead of only a single character.
+ by combining characters, instead of only a single character, or as a
+ :class:`complexchar` cell.
.. method:: window.addnstr(str, n[, attr])
background character.
.. versionchanged:: next
- Wide and combining characters are now accepted.
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted.
.. method:: window.bkgdset(ch[, attr])
the character through any scrolling and insert/delete line/character operations.
.. versionchanged:: next
- Wide and combining characters are now accepted.
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted.
.. method:: window.border([ls[, rs[, ts[, bs[, tl[, tr[, bl[, br]]]]]]]])
+-----------+---------------------+-----------------------+
.. versionchanged:: next
- Wide and combining characters are now accepted. A single call cannot mix
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted. A single call cannot mix
them with integer or byte characters.
*bs* are *horch*. The default corner characters are always used by this function.
.. versionchanged:: next
- Wide and combining characters are now accepted. A single call cannot mix
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted. A single call cannot mix
them with integer or byte characters.
on the window.
.. versionchanged:: next
- Wide and combining characters are now accepted.
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted.
.. method:: window.enclose(y, x)
Return the given window's current background character/attribute pair.
+.. method:: window.getbkgrnd()
+
+ Return the given window's current background as a :class:`complexchar`.
+ This is the wide-character variant of :meth:`getbkgd`: the returned object
+ carries the background character together with its attributes and color pair,
+ and the color pair is not limited to the value that fits in a
+ :func:`color_pair`.
+
+ This method is only available if Python was built against a wide-character
+ version of the underlying curses library.
+
+ .. versionadded:: next
+
+
.. method:: window.getch([y, x])
Get a character. Note that the integer returned does *not* have to be in ASCII
of the window if fewer than *n* cells are available.
.. versionchanged:: next
- Wide and combining characters are now accepted.
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted.
.. method:: window.idcok(flag)
the character proper, and upper bits are the attributes.
+.. method:: window.in_wch([y, x])
+
+ Return the complex character at the given position in the window as a
+ :class:`complexchar`. This is the wide-character variant of :meth:`inch`:
+ the returned object carries the cell's text (a spacing character optionally
+ followed by combining characters) together with its attributes and color
+ pair, none of which :meth:`inch` can represent.
+
+ This method is only available if Python was built against a wide-character
+ version of the underlying curses library.
+
+ .. versionadded:: next
+
+
.. method:: window.insch(ch[, attr])
window.insch(y, x, ch[, attr])
line being lost. The cursor position does not change.
.. versionchanged:: next
- Wide and combining characters are now accepted.
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted.
.. method:: window.insdelln(nlines)
character *ch* with attributes *attr*.
.. versionchanged:: next
- Wide and combining characters are now accepted.
+ Wide and combining characters, and :class:`complexchar` cells, are now
+ accepted.
.. _curses-screen-objects:
.. versionadded:: next
+.. _curses-complexchar-objects:
+
+Complex character objects
+-------------------------
+
+.. class:: complexchar(text, /, attr=0, pair=0)
+
+ A *complex character* (or *complexchar*) is an immutable styled
+ wide-character cell: a spacing character optionally followed by combining
+ characters, together with a set of attributes and a color pair.
+
+ *text* is the cell's text, *attr* a combination of the
+ :ref:`WA_* attributes <curses-wa-constants>` (equivalent to the matching
+ ``A_*`` constants), and *pair* a color pair number. Unlike the packed
+ :class:`chtype <int>` used by :meth:`~window.inch` and the ``A_*`` methods,
+ the color pair is stored separately and is not limited to the value that
+ fits in a :func:`color_pair`.
+
+ Complex characters are returned by :meth:`window.in_wch` and
+ :meth:`window.getbkgrnd`, and are accepted (along with an integer, a byte
+ or a string) by the character-cell methods such as :meth:`window.addch`,
+ :meth:`window.insch`, :meth:`window.bkgd`, :meth:`window.border`,
+ :meth:`window.hline` and :meth:`window.vline`. A complex character already
+ carries its own rendition, so it cannot be combined with an explicit *attr*
+ argument.
+
+ :func:`str` returns the cell's text; two complex characters are equal when
+ their text, attributes and color pair all match.
+
+ This type is only available if Python was built against a wide-character
+ version of the underlying curses library.
+
+ .. attribute:: attr
+
+ The attributes of the character cell (read-only).
+
+ .. attribute:: pair
+
+ The color pair number of the character cell (read-only).
+
+ .. versionadded:: next
+
+
Constants
---------
attribute value, and the corresponding ``WA_*`` attribute constants.
(Contributed by Serhiy Storchaka in :gh:`152219`.)
+* Add the :class:`curses.complexchar` type, representing a styled
+ wide-character cell (its text, attributes and color pair), and the window
+ methods :meth:`~curses.window.in_wch` and :meth:`~curses.window.getbkgrnd`
+ that return one --- the wide-character counterparts of
+ :meth:`~curses.window.inch` and :meth:`~curses.window.getbkgd`. The
+ character-cell methods, such as :meth:`~curses.window.addch` and
+ :meth:`~curses.window.border`, now also accept a
+ :class:`~curses.complexchar`.
+ (Contributed by Serhiy Storchaka in :gh:`152233`.)
+
gzip
----
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(asend));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ast));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(athrow));
+ _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(attr));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(attribute));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(autocommit));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(backtick));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pad));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(padded));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pages));
+ _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pair));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(parameter));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(parent));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(password));
STRUCT_FOR_ID(asend)
STRUCT_FOR_ID(ast)
STRUCT_FOR_ID(athrow)
+ STRUCT_FOR_ID(attr)
STRUCT_FOR_ID(attribute)
STRUCT_FOR_ID(autocommit)
STRUCT_FOR_ID(backtick)
STRUCT_FOR_ID(pad)
STRUCT_FOR_ID(padded)
STRUCT_FOR_ID(pages)
+ STRUCT_FOR_ID(pair)
STRUCT_FOR_ID(parameter)
STRUCT_FOR_ID(parent)
STRUCT_FOR_ID(password)
INIT_ID(asend), \
INIT_ID(ast), \
INIT_ID(athrow), \
+ INIT_ID(attr), \
INIT_ID(attribute), \
INIT_ID(autocommit), \
INIT_ID(backtick), \
INIT_ID(pad), \
INIT_ID(padded), \
INIT_ID(pages), \
+ INIT_ID(pair), \
INIT_ID(parameter), \
INIT_ID(parent), \
INIT_ID(password), \
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
+ string = &_Py_ID(attr);
+ _PyUnicode_InternStatic(interp, &string);
+ assert(_PyUnicode_CheckConsistency(string, 1));
+ assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(attribute);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
+ string = &_Py_ID(pair);
+ _PyUnicode_InternStatic(interp, &string);
+ assert(_PyUnicode_CheckConsistency(string, 1));
+ assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(parameter);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
# border() and box() cannot mix integer and wide-string characters.
self.assertRaises(TypeError, stdscr.box, vline, ord('-'))
+ @requires_curses_func('complexchar')
+ def test_complexchar_in_cell_methods(self):
+ # Every single-character-cell method also accepts a complexchar, whose
+ # attributes and color pair come from the cell itself.
+ stdscr = self.stdscr
+ cc = curses.complexchar('A', curses.A_BOLD)
+ v = curses.complexchar('|')
+ h = curses.complexchar('-')
+ stdscr.move(0, 0)
+ stdscr.addch(0, 0, cc)
+ self.assertEqual(str(stdscr.in_wch(0, 0)), 'A')
+ self.assertTrue(stdscr.in_wch(0, 0).attr & curses.A_BOLD)
+ stdscr.insch(1, 0, cc)
+ stdscr.echochar(cc)
+ stdscr.bkgdset(cc)
+ stdscr.bkgd(cc)
+ stdscr.hline(2, 0, h, 3)
+ stdscr.vline(3, 0, v, 3)
+ stdscr.border(v, v, h, h)
+ stdscr.box(v, h)
+ # A complexchar already carries its rendition, so combining it with an
+ # explicit attr argument is rejected.
+ self.assertRaises(TypeError, stdscr.addch, cc, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.addch, 0, 0, cc, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.insch, cc, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.echochar, cc, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.bkgd, cc, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.bkgdset, cc, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.hline, h, 3, curses.A_BOLD)
+ self.assertRaises(TypeError, stdscr.vline, v, 3, curses.A_BOLD)
@requires_curses_window_meth('in_wstr')
def test_in_wstr(self):
self.assertEqual(stdscr.in_wstr(0, 0, len(s)), s)
self.assertIsInstance(stdscr.instr(0, 0, len(s)), bytes)
+ @requires_curses_func('complexchar')
+ def test_complexchar(self):
+ # A complexchar is a styled wide-character cell: str() is its text,
+ # and the attr and pair attributes are its rendition.
+ cc = curses.complexchar('A', curses.A_BOLD)
+ self.assertEqual(str(cc), 'A')
+ self.assertTrue(cc.attr & curses.A_BOLD)
+ self.assertEqual(cc.pair, 0)
+ # A spacing character optionally followed by combining characters.
+ if self._encodable('e\u0301'):
+ self.assertEqual(str(curses.complexchar('e\u0301')), 'e\u0301')
+ # Defaults: no attributes, color pair 0.
+ cc = curses.complexchar('z')
+ self.assertEqual(str(cc), 'z')
+ self.assertEqual(cc.attr, 0)
+ self.assertEqual(cc.pair, 0)
+ # Immutable rendition.
+ self.assertRaises(AttributeError, setattr, cc, 'attr', 1)
+ self.assertRaises(AttributeError, setattr, cc, 'pair', 1)
+ # Equality and hashing compare text, attributes and color pair.
+ self.assertEqual(curses.complexchar('A', curses.A_BOLD),
+ curses.complexchar('A', curses.A_BOLD))
+ self.assertEqual(hash(curses.complexchar('A', curses.A_BOLD)),
+ hash(curses.complexchar('A', curses.A_BOLD)))
+ self.assertNotEqual(curses.complexchar('A'),
+ curses.complexchar('A', curses.A_BOLD))
+ self.assertNotEqual(curses.complexchar('A'), curses.complexchar('B'))
+ # repr() shows only a non-default attr/pair, and is a constructor call.
+ ns = {'_curses': sys.modules[type(cc).__module__]}
+ self.assertNotIn('attr=', repr(curses.complexchar('z')))
+ self.assertNotIn('pair=', repr(curses.complexchar('z')))
+ r = repr(curses.complexchar('A', curses.A_BOLD))
+ self.assertIn('attr=', r)
+ self.assertNotIn('pair=', r)
+ self.assertEqual(eval(r, ns), curses.complexchar('A', curses.A_BOLD))
+ # Invalid arguments.
+ self.assertRaises(TypeError, curses.complexchar, 65)
+ self.assertRaises(TypeError, curses.complexchar, 'A', 'bold')
+ self.assertRaises(OverflowError, curses.complexchar, 'A', -1)
+ self.assertRaises(OverflowError, curses.complexchar, 'A', 1 << 64)
+ self.assertRaises(ValueError, curses.complexchar, 'A', 0, -1)
+ self.assertRaises(ValueError, curses.complexchar, 'ab')
+
+ @requires_curses_window_meth('in_wch')
+ def test_in_wch(self):
+ # in_wch() returns the styled wide cell as a complexchar -- something
+ # inch() (a packed chtype) cannot represent.
+ stdscr = self.stdscr
+ stdscr.addch(0, 0, curses.complexchar('A', curses.A_UNDERLINE))
+ cc = stdscr.in_wch(0, 0)
+ self.assertEqual(str(cc), 'A')
+ self.assertTrue(cc.attr & curses.A_UNDERLINE)
+ if self._encodable('\u00e9'): # precomposed, for a portable round-trip
+ stdscr.addch(3, 0, curses.complexchar('\u00e9'))
+ self.assertEqual(str(stdscr.in_wch(3, 0)), '\u00e9')
+ # in_wch() without coordinates reads at the cursor position.
+ stdscr.move(0, 0)
+ self.assertEqual(str(stdscr.in_wch()), 'A')
+
+ @requires_curses_window_meth('in_wch')
+ @requires_colors
+ def test_in_wch_color(self):
+ # Unlike the chtype methods (which pack the pair into the value via
+ # COLOR_PAIR), a complex character carries its color pair separately.
+ stdscr = self.stdscr
+ curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
+ stdscr.addch(0, 0, curses.complexchar('A', curses.A_BOLD, 1))
+ cc = stdscr.in_wch(0, 0)
+ self.assertEqual(str(cc), 'A')
+ self.assertTrue(cc.attr & curses.A_BOLD)
+ self.assertEqual(cc.pair, 1)
+ self.assertEqual(curses.complexchar('A', 0, 1).pair, 1)
+
+ @requires_curses_window_meth('getbkgrnd')
+ def test_getbkgrnd(self):
+ # getbkgrnd() returns the background as a complexchar (getbkgd() can
+ # only return a packed chtype).
+ stdscr = self.stdscr
+ stdscr.bkgdset(curses.complexchar(' ', curses.A_DIM))
+ stdscr.bkgd(curses.complexchar(' ', curses.A_BOLD))
+ cc = stdscr.getbkgrnd()
+ self.assertEqual(str(cc), ' ')
+ self.assertTrue(cc.attr & curses.A_BOLD)
+
def test_output_character(self):
stdscr = self.stdscr
--- /dev/null
+Add the :class:`curses.complexchar` type, representing a styled wide-character
+cell (text, attributes and color pair), and the :mod:`curses` window methods
+:meth:`~curses.window.in_wch` and :meth:`~curses.window.getbkgrnd` that return
+one. The character-cell methods (:meth:`~curses.window.addch`,
+:meth:`~curses.window.bkgd`, :meth:`~curses.window.border`,
+:meth:`~curses.window.hline` and others) now also accept a
+:class:`~curses.complexchar`.
PyObject *error; // curses exception type
PyTypeObject *window_type; // exposed by PyCursesWindow_Type
PyTypeObject *screen_type; // _curses.screen
+#ifdef HAVE_NCURSESW
+ PyTypeObject *complexchar_type; // _curses.complexchar
+#endif
PyObject *topscreen; // owned ref to the current screen object,
// or NULL for the initscr() screen
} cursesmodule_state;
module _curses
class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type"
class _curses.screen "PyCursesScreenObject *" "clinic_state()->screen_type"
+class _curses.complexchar "PyCursesComplexCharObject *" "clinic_state()->complexchar_type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b027ab105ab94e1]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=211a02287a60aed0]*/
/* Indicate whether the module has already been loaded or not. */
static int curses_module_loaded = 0;
- 2 if obj is a character (written into *wch)
- 1 if obj is a byte (written into *ch)
- 0 on error: raise an exception */
+#ifdef HAVE_NCURSESW
+/* Convert a str -- a spacing character optionally followed by up to
+ CCHARW_MAX - 1 combining characters -- into a wide-character cell.
+ wch must point to a buffer of at least CCHARW_MAX + 1 wide characters.
+ Return 0 on success, -1 with an exception set on error. */
+static int
+PyCurses_ConvertToWideCell(PyObject *obj, wchar_t *wch)
+{
+ assert(PyUnicode_Check(obj));
+ Py_ssize_t nch = PyUnicode_AsWideChar(obj, wch, CCHARW_MAX + 1);
+ if (nch < 0) {
+ return -1;
+ }
+ if (nch == 0 || nch > CCHARW_MAX) {
+ PyErr_Format(PyExc_TypeError,
+ "expect a string of 1 to %d characters, "
+ "got a str of length %zi",
+ (int)CCHARW_MAX, PyUnicode_GET_LENGTH(obj));
+ return -1;
+ }
+ /* A lone control character is allowed (like addch(ord('\n'))), but in a
+ multi-character cell the base must be a printable spacing character and
+ the rest zero-width combining characters. Check explicitly: otherwise
+ setcchar() would silently drop a trailing spacing character, or fail
+ with a generic error for a control-character base. */
+ if (nch > 1) {
+ int bad = wcwidth(wch[0]) < 0;
+ for (Py_ssize_t i = 1; !bad && i < nch; i++) {
+ bad = wcwidth(wch[i]) != 0;
+ }
+ if (bad) {
+ PyErr_Format(PyExc_ValueError,
+ "a character cell must be a single spacing character "
+ "optionally followed by up to %d combining characters",
+ (int)(CCHARW_MAX - 1));
+ return -1;
+ }
+ }
+ return 0;
+}
+#endif
+
static int
PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj,
chtype *ch
if (PyUnicode_Check(obj)) {
#ifdef HAVE_NCURSESW
- /* A character cell may hold a spacing character plus up to
- CCHARW_MAX - 1 combining characters; wch must point to a buffer
- of at least CCHARW_MAX + 1 wide characters. */
- Py_ssize_t nch = PyUnicode_AsWideChar(obj, wch, CCHARW_MAX + 1);
- if (nch < 0) {
- return 0;
- }
- if (nch == 0 || nch > CCHARW_MAX) {
- PyErr_Format(PyExc_TypeError,
- "expect int or bytes or a string of 1 to %d "
- "characters, got a str of length %zi",
- (int)CCHARW_MAX, PyUnicode_GET_LENGTH(obj));
+ if (PyCurses_ConvertToWideCell(obj, wch) < 0) {
return 0;
}
- /* A character cell is a single spacing character optionally followed
- by combining characters. A lone control character is still allowed
- (like addch(ord('\n'))), but in a multi-character cell the base must
- be a printable character and the rest must be zero-width combining
- characters. Validate this explicitly: otherwise setcchar() would
- silently drop a trailing spacing character, or fail with a generic
- error for a control character used as the base. */
- if (nch > 1) {
- int bad = wcwidth(wch[0]) < 0;
- for (Py_ssize_t i = 1; !bad && i < nch; i++) {
- bad = wcwidth(wch[i]) != 0;
- }
- if (bad) {
- PyErr_SetString(PyExc_ValueError,
- "a character cell must be a single spacing "
- "character optionally followed by combining "
- "characters");
- return 0;
- }
- }
return 2;
#else
return PyCurses_ConvertToChtype(win, obj, ch);
}
#ifdef HAVE_NCURSESW
+typedef struct {
+ PyObject_HEAD
+ cchar_t cval;
+} PyCursesComplexCharObject;
+
+#define _PyCursesComplexCharObject_CAST(op) ((PyCursesComplexCharObject *)(op))
+
/* Build a single character cell from obj.
- On success return 1 and store the raw chtype (without *attr*) in *pch when
- obj is an int or bytes, or return 2 and store a cchar_t (with *attr*
- applied) in *pwc when obj is a str -- a spacing character optionally
- followed by combining characters. Return 0 and set an exception on error.
+ Return 1 and store a chtype in *pch for an int or bytes, 2 and store a
+ cchar_t (with *attr* applied) in *pwc for a str (a spacing character
+ optionally followed by combining characters), or 0 with an exception set.
- This lets a method use the wide *_set functions (which accept combining
- characters) for string arguments while still accepting integer chtype
- values. */
+ obj may also be a complexchar, whose cell is used directly; it carries its
+ own rendition, so supplying *attr* too (attr_given) is rejected. */
static int
PyCurses_ConvertToCell(PyCursesWindowObject *win, PyObject *obj, long attr,
- const char *funcname, chtype *pch, cchar_t *pwc)
+ int attr_given, const char *funcname,
+ chtype *pch, cchar_t *pwc)
{
+ cursesmodule_state *state = get_cursesmodule_state_by_win(win);
+ if (Py_IS_TYPE(obj, state->complexchar_type)) {
+ if (attr_given) {
+ PyErr_Format(PyExc_TypeError,
+ "%s(): attr cannot be specified together with "
+ "a complexchar", funcname);
+ return 0;
+ }
+ *pwc = _PyCursesComplexCharObject_CAST(obj)->cval;
+ return 2;
+ }
wchar_t wstr[CCHARW_MAX + 1];
int type = PyCurses_ConvertToCchar_t(win, obj, pch, wstr);
if (type == 2) {
}
return type;
}
+
+/* Pack a wide-character cell, routing the color pair through the
+ extended-color opts slot so it is not limited to a short (unlike the
+ chtype COLOR_PAIR field). Without that slot the pair must fit in the
+ short that setcchar() takes; raise OverflowError instead of silently
+ truncating a larger one. */
+static int
+curses_setcchar(cchar_t *wcval, const wchar_t *wstr, attr_t attrs, int pair)
+{
+#if _NCURSES_EXTENDED_COLOR_FUNCS
+ /* The pair passed through the opts slot is authoritative and may exceed
+ a short; ncurses then ignores the short argument, but clamp it into
+ range so the int-to-short narrowing stays well-defined. */
+ short spair = pair <= SHRT_MAX ? (short)pair : SHRT_MAX;
+ return setcchar(wcval, wstr, attrs, spair, &pair);
+#else
+ if (pair > SHRT_MAX) {
+ PyErr_Format(PyExc_OverflowError,
+ "color pair %d does not fit in a short", pair);
+ return ERR;
+ }
+ return setcchar(wcval, wstr, attrs, (short)pair, NULL);
+#endif
+}
+
+/* Unpack a wide-character cell into its text, attributes and color pair.
+ The pair is read through the extended-color opts slot when available, so
+ values above SHRT_MAX are preserved. */
+static int
+curses_getcchar(const cchar_t *wcval, wchar_t *wstr, attr_t *attrs, int *pair)
+{
+ short spair = 0;
+#if _NCURSES_EXTENDED_COLOR_FUNCS
+ int rtn = getcchar(wcval, wstr, attrs, &spair, pair);
+#else
+ int rtn = getcchar(wcval, wstr, attrs, &spair, NULL);
+ if (rtn != ERR) {
+ *pair = spair;
+ }
+#endif
+ return rtn;
+}
+
+/* Hash one cell by value (text, attributes, pair) -- consistent with the
+ equality comparison, not the raw cchar_t whose padding and unused text tail
+ it ignores. Zero the key first so those bytes are deterministic, then
+ unpack into it. Returns -1 with an exception set on the (practically
+ impossible) getcchar() failure. */
+static Py_hash_t
+curses_cchar_hash(cursesmodule_state *state, const cchar_t *cell)
+{
+ struct {
+ attr_t attrs;
+ int pair;
+ wchar_t wstr[CCHARW_MAX + 1];
+ } key;
+ memset(&key, 0, sizeof(key));
+ if (curses_getcchar(cell, key.wstr, &key.attrs, &key.pair) == ERR) {
+ PyErr_SetString(state->error, "getcchar() returned ERR");
+ return -1;
+ }
+ return Py_HashBuffer(&key, sizeof(key));
+}
#endif
static int
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=6132d3d99d3ec25a]*/
+#ifdef HAVE_NCURSESW
+/* -------------------------------------------------------*/
+/* Complex character objects (styled wide-character cells) */
+/* -------------------------------------------------------*/
+
+/* Wrap a cchar_t in a new complexchar object (the read side: in_wch,
+ getbkgrnd, ...). The object simply owns a copy of the cell. */
+static PyObject *
+PyCursesComplexChar_New(cursesmodule_state *state, const cchar_t *wcval)
+{
+ PyCursesComplexCharObject *cc =
+ PyObject_New(PyCursesComplexCharObject, state->complexchar_type);
+ if (cc == NULL) {
+ return NULL;
+ }
+ cc->cval = *wcval;
+ return (PyObject *)cc;
+}
+
+/* Decode the cell, raising curses.error on the (practically impossible)
+ getcchar() failure. */
+static int
+complexchar_unpack(PyObject *self, wchar_t *wstr, attr_t *attrs, int *pair)
+{
+ cchar_t *cval = &_PyCursesComplexCharObject_CAST(self)->cval;
+ if (curses_getcchar(cval, wstr, attrs, pair) == ERR) {
+ cursesmodule_state *state =
+ get_cursesmodule_state_by_cls(Py_TYPE(self));
+ PyErr_SetString(state->error, "getcchar() returned ERR");
+ return -1;
+ }
+ return 0;
+}
+
+/*[clinic input]
+@classmethod
+_curses.complexchar.__new__ as complexchar_new
+
+ text: unicode
+ A spacing character optionally followed by combining characters.
+ /
+ attr: attr = 0
+ The attributes of the character cell.
+ pair: int = 0
+ The color pair number of the character cell.
+
+A styled wide-character cell.
+
+text is a spacing character optionally followed by combining
+characters. attr is a set of attributes (the WA_* constants) and pair
+is a color pair number. The object is immutable; str(cc) returns its
+text, and the attr and pair attributes return its rendition.
+[clinic start generated code]*/
+
+static PyObject *
+complexchar_new_impl(PyTypeObject *type, PyObject *text, attr_t attr,
+ int pair)
+/*[clinic end generated code: output=5d8173048826b946 input=c3f3466a2656a196]*/
+{
+ if (pair < 0) {
+ PyErr_SetString(PyExc_ValueError, "color pair is less than 0");
+ return NULL;
+ }
+ wchar_t wstr[CCHARW_MAX + 1];
+ if (PyCurses_ConvertToWideCell(text, wstr) < 0) {
+ return NULL;
+ }
+ cchar_t cval;
+ if (curses_setcchar(&cval, wstr, attr, pair) == ERR) {
+ if (!PyErr_Occurred()) {
+ cursesmodule_state *state = get_cursesmodule_state_by_cls(type);
+ PyErr_SetString(state->error, "setcchar() returned ERR");
+ }
+ return NULL;
+ }
+ PyCursesComplexCharObject *cc =
+ (PyCursesComplexCharObject *)type->tp_alloc(type, 0);
+ if (cc == NULL) {
+ return NULL;
+ }
+ cc->cval = cval;
+ return (PyObject *)cc;
+}
+
+static void
+complexchar_dealloc(PyObject *self)
+{
+ PyTypeObject *tp = Py_TYPE(self);
+ tp->tp_free(self);
+ Py_DECREF(tp);
+}
+
+static PyObject *
+complexchar_str(PyObject *self)
+{
+ wchar_t wstr[CCHARW_MAX + 1];
+ attr_t attrs;
+ int pair;
+ if (complexchar_unpack(self, wstr, &attrs, &pair) < 0) {
+ return NULL;
+ }
+ return PyUnicode_FromWideChar(wstr, -1);
+}
+
+static PyObject *
+complexchar_repr(PyObject *self)
+{
+ wchar_t wstr[CCHARW_MAX + 1];
+ attr_t attrs;
+ int pair;
+ if (complexchar_unpack(self, wstr, &attrs, &pair) < 0) {
+ return NULL;
+ }
+ PyObject *text = PyUnicode_FromWideChar(wstr, -1);
+ if (text == NULL) {
+ return NULL;
+ }
+ /* Show attr and pair only when not at their defaults. */
+ PyObject *res;
+ if (attrs == 0 && pair == 0) {
+ res = PyUnicode_FromFormat("%T(%R)", self, text);
+ }
+ else if (pair == 0) {
+ res = PyUnicode_FromFormat("%T(%R, attr=%lu)", self, text,
+ (unsigned long)attrs);
+ }
+ else if (attrs == 0) {
+ res = PyUnicode_FromFormat("%T(%R, pair=%d)", self, text, pair);
+ }
+ else {
+ res = PyUnicode_FromFormat("%T(%R, attr=%lu, pair=%d)", self, text,
+ (unsigned long)attrs, pair);
+ }
+ Py_DECREF(text);
+ return res;
+}
+
+static PyObject *
+complexchar_get_attr(PyObject *self, void *Py_UNUSED(closure))
+{
+ wchar_t wstr[CCHARW_MAX + 1];
+ attr_t attrs;
+ int pair;
+ if (complexchar_unpack(self, wstr, &attrs, &pair) < 0) {
+ return NULL;
+ }
+ return PyLong_FromUnsignedLong((unsigned long)attrs);
+}
+
+static PyObject *
+complexchar_get_pair(PyObject *self, void *Py_UNUSED(closure))
+{
+ wchar_t wstr[CCHARW_MAX + 1];
+ attr_t attrs;
+ int pair;
+ if (complexchar_unpack(self, wstr, &attrs, &pair) < 0) {
+ return NULL;
+ }
+ return PyLong_FromLong(pair);
+}
+
+static PyObject *
+complexchar_richcompare(PyObject *self, PyObject *other, int op)
+{
+ if ((op != Py_EQ && op != Py_NE) ||
+ !Py_IS_TYPE(other, Py_TYPE(self)))
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+ wchar_t wstr1[CCHARW_MAX + 1], wstr2[CCHARW_MAX + 1];
+ attr_t attrs1, attrs2;
+ int pair1, pair2;
+ if (complexchar_unpack(self, wstr1, &attrs1, &pair1) < 0 ||
+ complexchar_unpack(other, wstr2, &attrs2, &pair2) < 0)
+ {
+ return NULL;
+ }
+ int equal = (attrs1 == attrs2 && pair1 == pair2 &&
+ wcscmp(wstr1, wstr2) == 0);
+ return PyBool_FromLong(equal == (op == Py_EQ));
+}
+
+static Py_hash_t
+complexchar_hash(PyObject *self)
+{
+ cursesmodule_state *state = get_cursesmodule_state_by_cls(Py_TYPE(self));
+ return curses_cchar_hash(state, &_PyCursesComplexCharObject_CAST(self)->cval);
+}
+
+static PyGetSetDef complexchar_getsets[] = {
+ {"attr", complexchar_get_attr, NULL,
+ PyDoc_STR("the attributes of the character cell"), NULL},
+ {"pair", complexchar_get_pair, NULL,
+ PyDoc_STR("the color pair of the character cell"), NULL},
+ {NULL}
+};
+
+#endif
+
/*****************************************************************************
The Window Object
******************************************************************************/
Character to add.
[
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ attr: long
Attributes for the character.
]
/
_curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1,
int y, int x, PyObject *ch, int group_right_1,
long attr)
-/*[clinic end generated code: output=00f4c37af3378f45 input=95ce131578458196]*/
+/*[clinic end generated code: output=00f4c37af3378f45 input=ab196a1dac3d354c]*/
{
int coordinates_group = group_left_1;
int rtn;
int type;
chtype cch = 0;
#ifdef HAVE_NCURSESW
- wchar_t wstr[CCHARW_MAX + 1];
cchar_t wcval;
#endif
const char *funcname;
#ifdef HAVE_NCURSESW
- type = PyCurses_ConvertToCchar_t(self, ch, &cch, wstr);
+ type = PyCurses_ConvertToCell(self, ch, attr, group_right_1, "addch",
+ &cch, &wcval);
if (type == 2) {
- rtn = setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL);
- if (rtn == ERR) {
- curses_window_set_error(self, "setcchar", "addch");
- return NULL;
- }
if (coordinates_group) {
rtn = mvwadd_wch(self->win,y,x, &wcval);
funcname = "mvwadd_wch";
ch: object
Background character.
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ [
+ attr: long
Background attributes.
+ ]
/
Set the background property of the window.
[clinic start generated code]*/
static PyObject *
-_curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr)
-/*[clinic end generated code: output=058290afb2cf4034 input=634015bcb339283d]*/
+_curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch,
+ int group_right_1, long attr)
+/*[clinic end generated code: output=73cb11ecca59612f input=a2129c1b709db432]*/
{
chtype bkgd;
#ifdef HAVE_NCURSESW
cchar_t wch;
- int type = PyCurses_ConvertToCell(self, ch, attr, "bkgd", &bkgd, &wch);
+ int type = PyCurses_ConvertToCell(self, ch, attr, group_right_1,
+ "bkgd", &bkgd, &wch);
if (type == 0) {
return NULL;
}
ch: object
Background character.
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ [
+ attr: long
Background attributes.
+ ]
/
Set the window's background.
static PyObject *
_curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch,
- long attr)
-/*[clinic end generated code: output=8cb994fc4d7e2496 input=e09c682425c9e45b]*/
+ int group_right_1, long attr)
+/*[clinic end generated code: output=3c32f2de5685a482 input=1f0811b24af821ca]*/
{
chtype bkgd;
#ifdef HAVE_NCURSESW
cchar_t wch;
- int type = PyCurses_ConvertToCell(self, ch, attr, "bkgdset", &bkgd, &wch);
+ int type = PyCurses_ConvertToCell(self, ch, attr, group_right_1,
+ "bkgdset", &bkgd, &wch);
if (type == 0) {
return NULL;
}
for (i = 0; i < 8; i++) {
types[i] = 0;
if (objs[i] != NULL) {
- types[i] = PyCurses_ConvertToCell(self, objs[i], A_NORMAL,
+ types[i] = PyCurses_ConvertToCell(self, objs[i], A_NORMAL, 0,
"border", &ch[i], &wch[i]);
if (types[i] == 0) {
return NULL;
cchar_t wch1, wch2;
int t1 = 0, t2 = 0;
if (group_right_1) {
- t1 = PyCurses_ConvertToCell(self, verch, A_NORMAL, "box", &ch1, &wch1);
+ t1 = PyCurses_ConvertToCell(self, verch, A_NORMAL, 0, "box", &ch1, &wch1);
if (t1 == 0) {
return NULL;
}
- t2 = PyCurses_ConvertToCell(self, horch, A_NORMAL, "box", &ch2, &wch2);
+ t2 = PyCurses_ConvertToCell(self, horch, A_NORMAL, 0, "box", &ch2, &wch2);
if (t2 == 0) {
return NULL;
}
ch: object
Character to add.
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ [
+ attr: long
Attributes for the character.
+ ]
/
Add character ch with attribute attr, and refresh.
static PyObject *
_curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch,
- long attr)
-/*[clinic end generated code: output=13e7dd875d4b9642 input=e7f34b964e92b156]*/
+ int group_right_1, long attr)
+/*[clinic end generated code: output=f42da9e200c935e5 input=26e16855ec1b0e78]*/
{
chtype ch_;
#ifdef HAVE_NCURSESW
cchar_t wch;
- int type = PyCurses_ConvertToCell(self, ch, attr, "echochar", &ch_, &wch);
+ int type = PyCurses_ConvertToCell(self, ch, attr, group_right_1,
+ "echochar", &ch_, &wch);
if (type == 0) {
return NULL;
}
return PyLong_FromLong(rtn);
}
+#ifdef HAVE_NCURSESW
+/*[clinic input]
+_curses.window.in_wch
+
+ [
+ y: int
+ Y-coordinate.
+ x: int
+ X-coordinate.
+ ]
+ /
+
+Return the complex character at the given position in the window.
+
+The returned object is a complexchar carrying the cell's text,
+attributes and color pair.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_in_wch_impl(PyCursesWindowObject *self, int group_right_1,
+ int y, int x)
+/*[clinic end generated code: output=846ca8a82f2ecab4 input=a55dd215367dfbb1]*/
+{
+ cchar_t wcval;
+ int rtn;
+ const char *funcname;
+ if (group_right_1) {
+ rtn = mvwin_wch(self->win, y, x, &wcval);
+ funcname = "mvwin_wch";
+ }
+ else {
+ rtn = win_wch(self->win, &wcval);
+ funcname = "win_wch";
+ }
+ if (rtn == ERR) {
+ curses_window_set_error(self, funcname, "in_wch");
+ return NULL;
+ }
+ cursesmodule_state *state = get_cursesmodule_state_by_win(self);
+ return PyCursesComplexChar_New(state, &wcval);
+}
+
+/*[clinic input]
+_curses.window.getbkgrnd
+
+Return the window's current background complex character.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_getbkgrnd_impl(PyCursesWindowObject *self)
+/*[clinic end generated code: output=afec19cad00eff71 input=e06bf3d6bf90d2ec]*/
+{
+ cchar_t wcval;
+ if (wgetbkgrnd(self->win, &wcval) == ERR) {
+ curses_window_set_error(self, "wgetbkgrnd", "getbkgrnd");
+ return NULL;
+ }
+ cursesmodule_state *state = get_cursesmodule_state_by_win(self);
+ return PyCursesComplexChar_New(state, &wcval);
+}
+
+#endif /* HAVE_NCURSESW */
+
static PyObject *
curses_check_signals_on_input_error(PyCursesWindowObject *self,
const char *curses_funcname,
Line length.
[
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ attr: long
Attributes for the characters.
]
/
_curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1,
int y, int x, PyObject *ch, int n,
int group_right_1, long attr)
-/*[clinic end generated code: output=c00d489d61fc9eef input=81a4dea47268163e]*/
+/*[clinic end generated code: output=c00d489d61fc9eef input=924f8c28521bc2ec]*/
{
chtype ch_;
#ifdef HAVE_NCURSESW
cchar_t wch;
- int type = PyCurses_ConvertToCell(self, ch, attr, "hline", &ch_, &wch);
+ int type = PyCurses_ConvertToCell(self, ch, attr, group_right_1, "hline",
+ &ch_, &wch);
if (type == 0) {
return NULL;
}
Character to insert.
[
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ attr: long
Attributes for the character.
]
/
_curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1,
int y, int x, PyObject *ch, int group_right_1,
long attr)
-/*[clinic end generated code: output=ade8cfe3a3bf3e34 input=d662a0f96f33e15a]*/
+/*[clinic end generated code: output=ade8cfe3a3bf3e34 input=47d2989159ae6ca7]*/
{
int rtn;
chtype ch_ = 0;
const char *funcname;
#ifdef HAVE_NCURSESW
cchar_t wch;
- int type = PyCurses_ConvertToCell(self, ch, attr, "insch", &ch_, &wch);
+ int type = PyCurses_ConvertToCell(self, ch, attr, group_right_1, "insch",
+ &ch_, &wch);
if (type == 0) {
return NULL;
}
Line length.
[
- attr: long(c_default="A_NORMAL") = _curses.A_NORMAL
+ attr: long
Attributes for the character.
]
/
_curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1,
int y, int x, PyObject *ch, int n,
int group_right_1, long attr)
-/*[clinic end generated code: output=287ad1cc8982217f input=a6f2dc86a4648b32]*/
+/*[clinic end generated code: output=287ad1cc8982217f input=1d4aa27ff0309bbc]*/
{
chtype ch_;
#ifdef HAVE_NCURSESW
cchar_t wch;
- int type = PyCurses_ConvertToCell(self, ch, attr, "vline", &ch_, &wch);
+ int type = PyCurses_ConvertToCell(self, ch, attr, group_right_1, "vline",
+ &ch_, &wch);
if (type == 0) {
return NULL;
}
#define clinic_state() (get_cursesmodule_state_by_cls(Py_TYPE(self)))
#include "clinic/_cursesmodule.c.h"
+
+#ifdef HAVE_NCURSESW
+static PyType_Slot PyCursesComplexChar_Type_slots[] = {
+ {Py_tp_doc, (void *)complexchar_new__doc__},
+ {Py_tp_new, complexchar_new},
+ {Py_tp_dealloc, complexchar_dealloc},
+ {Py_tp_repr, complexchar_repr},
+ {Py_tp_str, complexchar_str},
+ {Py_tp_richcompare, complexchar_richcompare},
+ {Py_tp_hash, complexchar_hash},
+ {Py_tp_getset, complexchar_getsets},
+ {0, NULL}
+};
+
+static PyType_Spec PyCursesComplexChar_Type_spec = {
+ .name = "_curses.complexchar",
+ .basicsize = sizeof(PyCursesComplexCharObject),
+ .flags = Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_IMMUTABLETYPE
+ | Py_TPFLAGS_HEAPTYPE,
+ .slots = PyCursesComplexChar_Type_slots
+};
+#endif
#undef clinic_state
#if defined(HAVE_CURSES_USE_SCREEN) || defined(HAVE_CURSES_USE_WINDOW)
"getbegyx($self, /)\n--\n\n"
"Return a tuple (y, x) of the upper-left corner coordinates."},
_CURSES_WINDOW_GETBKGD_METHODDEF
+ _CURSES_WINDOW_GETBKGRND_METHODDEF
_CURSES_WINDOW_GETCH_METHODDEF
_CURSES_WINDOW_GETKEY_METHODDEF
_CURSES_WINDOW_GET_WCH_METHODDEF
"If flag is true, refresh the window on every change to it."},
#endif
_CURSES_WINDOW_INCH_METHODDEF
+ _CURSES_WINDOW_IN_WCH_METHODDEF
_CURSES_WINDOW_INSCH_METHODDEF
{"insdelln", PyCursesWindow_winsdelln, METH_VARARGS,
"insdelln($self, nlines, /)\n--\n\n"
Py_VISIT(state->error);
Py_VISIT(state->window_type);
Py_VISIT(state->screen_type);
+#ifdef HAVE_NCURSESW
+ Py_VISIT(state->complexchar_type);
+#endif
Py_VISIT(state->topscreen);
return 0;
}
Py_CLEAR(state->error);
Py_CLEAR(state->window_type);
Py_CLEAR(state->screen_type);
+#ifdef HAVE_NCURSESW
+ Py_CLEAR(state->complexchar_type);
+#endif
Py_CLEAR(state->topscreen);
return 0;
}
if (PyModule_AddType(module, state->screen_type) < 0) {
return -1;
}
+#ifdef HAVE_NCURSESW
+ state->complexchar_type = (PyTypeObject *)PyType_FromModuleAndSpec(
+ module, &PyCursesComplexChar_Type_spec, NULL);
+ if (state->complexchar_type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(module, state->complexchar_type) < 0) {
+ return -1;
+ }
+#endif
/* Add some symbolic constants to the module */
PyObject *module_dict = PyModule_GetDict(module);
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
-#include "pycore_modsupport.h" // _PyArg_CheckPositional()
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+#if defined(HAVE_NCURSESW)
+
+PyDoc_STRVAR(complexchar_new__doc__,
+"complexchar(text, /, attr=0, pair=0)\n"
+"--\n"
+"\n"
+"A styled wide-character cell.\n"
+"\n"
+" text\n"
+" A spacing character optionally followed by combining characters.\n"
+" attr\n"
+" The attributes of the character cell.\n"
+" pair\n"
+" The color pair number of the character cell.\n"
+"\n"
+"text is a spacing character optionally followed by combining\n"
+"characters. attr is a set of attributes (the WA_* constants) and pair\n"
+"is a color pair number. The object is immutable; str(cc) returns its\n"
+"text, and the attr and pair attributes return its rendition.");
+
+static PyObject *
+complexchar_new_impl(PyTypeObject *type, PyObject *text, attr_t attr,
+ int pair);
+
+static PyObject *
+complexchar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+ #define NUM_KEYWORDS 2
+ static struct {
+ PyGC_Head _this_is_not_used;
+ PyObject_VAR_HEAD
+ Py_hash_t ob_hash;
+ PyObject *ob_item[NUM_KEYWORDS];
+ } _kwtuple = {
+ .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+ .ob_hash = -1,
+ .ob_item = { &_Py_ID(attr), &_Py_ID(pair), },
+ };
+ #undef NUM_KEYWORDS
+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+ #else // !Py_BUILD_CORE
+ # define KWTUPLE NULL
+ #endif // !Py_BUILD_CORE
+
+ static const char * const _keywords[] = {"", "attr", "pair", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "complexchar",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[3];
+ PyObject * const *fastargs;
+ Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
+ PyObject *text;
+ attr_t attr = 0;
+ int pair = 0;
+
+ fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
+ /*minpos*/ 1, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+ if (!fastargs) {
+ goto exit;
+ }
+ if (!PyUnicode_Check(fastargs[0])) {
+ _PyArg_BadArgument("complexchar", "argument 1", "str", fastargs[0]);
+ goto exit;
+ }
+ text = fastargs[0];
+ if (!noptargs) {
+ goto skip_optional_pos;
+ }
+ if (fastargs[1]) {
+ if (!attr_converter(fastargs[1], &attr)) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_pos;
+ }
+ }
+ pair = PyLong_AsInt(fastargs[2]);
+ if (pair == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+skip_optional_pos:
+ return_value = complexchar_new_impl(type, text, attr, pair);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_NCURSESW) */
PyDoc_STRVAR(_curses_window_addch__doc__,
-"addch([y, x,] ch, [attr=_curses.A_NORMAL])\n"
+"addch([y, x,] ch, [attr])\n"
"Paint the character.\n"
"\n"
" y\n"
int x = 0;
PyObject *ch;
int group_right_1 = 0;
- long attr = A_NORMAL;
+ long attr = 0;
switch (PyTuple_GET_SIZE(args)) {
case 1:
}
PyDoc_STRVAR(_curses_window_bkgd__doc__,
-"bkgd($self, ch, attr=_curses.A_NORMAL, /)\n"
-"--\n"
-"\n"
+"bkgd(ch, [attr])\n"
"Set the background property of the window.\n"
"\n"
" ch\n"
" Background attributes.");
#define _CURSES_WINDOW_BKGD_METHODDEF \
- {"bkgd", _PyCFunction_CAST(_curses_window_bkgd), METH_FASTCALL, _curses_window_bkgd__doc__},
+ {"bkgd", (PyCFunction)_curses_window_bkgd, METH_VARARGS, _curses_window_bkgd__doc__},
static PyObject *
-_curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, long attr);
+_curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch,
+ int group_right_1, long attr);
static PyObject *
-_curses_window_bkgd(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
+_curses_window_bkgd(PyObject *self, PyObject *args)
{
PyObject *return_value = NULL;
PyObject *ch;
- long attr = A_NORMAL;
+ int group_right_1 = 0;
+ long attr = 0;
- if (!_PyArg_CheckPositional("bkgd", nargs, 1, 2)) {
- goto exit;
- }
- ch = args[0];
- if (nargs < 2) {
- goto skip_optional;
- }
- attr = PyLong_AsLong(args[1]);
- if (attr == -1 && PyErr_Occurred()) {
- goto exit;
+ switch (PyTuple_GET_SIZE(args)) {
+ case 1:
+ if (!PyArg_ParseTuple(args, "O:bkgd", &ch)) {
+ goto exit;
+ }
+ break;
+ case 2:
+ if (!PyArg_ParseTuple(args, "Ol:bkgd", &ch, &attr)) {
+ goto exit;
+ }
+ group_right_1 = 1;
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "_curses.window.bkgd requires 1 to 2 arguments");
+ goto exit;
}
-skip_optional:
- return_value = _curses_window_bkgd_impl((PyCursesWindowObject *)self, ch, attr);
+ return_value = _curses_window_bkgd_impl((PyCursesWindowObject *)self, ch, group_right_1, attr);
exit:
return return_value;
}
PyDoc_STRVAR(_curses_window_bkgdset__doc__,
-"bkgdset($self, ch, attr=_curses.A_NORMAL, /)\n"
-"--\n"
-"\n"
+"bkgdset(ch, [attr])\n"
"Set the window\'s background.\n"
"\n"
" ch\n"
" Background attributes.");
#define _CURSES_WINDOW_BKGDSET_METHODDEF \
- {"bkgdset", _PyCFunction_CAST(_curses_window_bkgdset), METH_FASTCALL, _curses_window_bkgdset__doc__},
+ {"bkgdset", (PyCFunction)_curses_window_bkgdset, METH_VARARGS, _curses_window_bkgdset__doc__},
static PyObject *
_curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch,
- long attr);
+ int group_right_1, long attr);
static PyObject *
-_curses_window_bkgdset(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
+_curses_window_bkgdset(PyObject *self, PyObject *args)
{
PyObject *return_value = NULL;
PyObject *ch;
- long attr = A_NORMAL;
+ int group_right_1 = 0;
+ long attr = 0;
- if (!_PyArg_CheckPositional("bkgdset", nargs, 1, 2)) {
- goto exit;
- }
- ch = args[0];
- if (nargs < 2) {
- goto skip_optional;
- }
- attr = PyLong_AsLong(args[1]);
- if (attr == -1 && PyErr_Occurred()) {
- goto exit;
+ switch (PyTuple_GET_SIZE(args)) {
+ case 1:
+ if (!PyArg_ParseTuple(args, "O:bkgdset", &ch)) {
+ goto exit;
+ }
+ break;
+ case 2:
+ if (!PyArg_ParseTuple(args, "Ol:bkgdset", &ch, &attr)) {
+ goto exit;
+ }
+ group_right_1 = 1;
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "_curses.window.bkgdset requires 1 to 2 arguments");
+ goto exit;
}
-skip_optional:
- return_value = _curses_window_bkgdset_impl((PyCursesWindowObject *)self, ch, attr);
+ return_value = _curses_window_bkgdset_impl((PyCursesWindowObject *)self, ch, group_right_1, attr);
exit:
return return_value;
}
PyDoc_STRVAR(_curses_window_echochar__doc__,
-"echochar($self, ch, attr=_curses.A_NORMAL, /)\n"
-"--\n"
-"\n"
+"echochar(ch, [attr])\n"
"Add character ch with attribute attr, and refresh.\n"
"\n"
" ch\n"
" Attributes for the character.");
#define _CURSES_WINDOW_ECHOCHAR_METHODDEF \
- {"echochar", _PyCFunction_CAST(_curses_window_echochar), METH_FASTCALL, _curses_window_echochar__doc__},
+ {"echochar", (PyCFunction)_curses_window_echochar, METH_VARARGS, _curses_window_echochar__doc__},
static PyObject *
_curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch,
- long attr);
+ int group_right_1, long attr);
static PyObject *
-_curses_window_echochar(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
+_curses_window_echochar(PyObject *self, PyObject *args)
{
PyObject *return_value = NULL;
PyObject *ch;
- long attr = A_NORMAL;
+ int group_right_1 = 0;
+ long attr = 0;
- if (!_PyArg_CheckPositional("echochar", nargs, 1, 2)) {
- goto exit;
- }
- ch = args[0];
- if (nargs < 2) {
- goto skip_optional;
- }
- attr = PyLong_AsLong(args[1]);
- if (attr == -1 && PyErr_Occurred()) {
- goto exit;
+ switch (PyTuple_GET_SIZE(args)) {
+ case 1:
+ if (!PyArg_ParseTuple(args, "O:echochar", &ch)) {
+ goto exit;
+ }
+ break;
+ case 2:
+ if (!PyArg_ParseTuple(args, "Ol:echochar", &ch, &attr)) {
+ goto exit;
+ }
+ group_right_1 = 1;
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "_curses.window.echochar requires 1 to 2 arguments");
+ goto exit;
}
-skip_optional:
- return_value = _curses_window_echochar_impl((PyCursesWindowObject *)self, ch, attr);
+ return_value = _curses_window_echochar_impl((PyCursesWindowObject *)self, ch, group_right_1, attr);
exit:
return return_value;
return _curses_window_getbkgd_impl((PyCursesWindowObject *)self);
}
+#if defined(HAVE_NCURSESW)
+
+PyDoc_STRVAR(_curses_window_in_wch__doc__,
+"in_wch([y, x])\n"
+"Return the complex character at the given position in the window.\n"
+"\n"
+" y\n"
+" Y-coordinate.\n"
+" x\n"
+" X-coordinate.\n"
+"\n"
+"The returned object is a complexchar carrying the cell\'s text,\n"
+"attributes and color pair.");
+
+#define _CURSES_WINDOW_IN_WCH_METHODDEF \
+ {"in_wch", (PyCFunction)_curses_window_in_wch, METH_VARARGS, _curses_window_in_wch__doc__},
+
+static PyObject *
+_curses_window_in_wch_impl(PyCursesWindowObject *self, int group_right_1,
+ int y, int x);
+
+static PyObject *
+_curses_window_in_wch(PyObject *self, PyObject *args)
+{
+ PyObject *return_value = NULL;
+ int group_right_1 = 0;
+ int y = 0;
+ int x = 0;
+
+ switch (PyTuple_GET_SIZE(args)) {
+ case 0:
+ break;
+ case 2:
+ if (!PyArg_ParseTuple(args, "ii:in_wch", &y, &x)) {
+ goto exit;
+ }
+ group_right_1 = 1;
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError, "_curses.window.in_wch requires 0 to 2 arguments");
+ goto exit;
+ }
+ return_value = _curses_window_in_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(HAVE_NCURSESW) */
+
+#if defined(HAVE_NCURSESW)
+
+PyDoc_STRVAR(_curses_window_getbkgrnd__doc__,
+"getbkgrnd($self, /)\n"
+"--\n"
+"\n"
+"Return the window\'s current background complex character.");
+
+#define _CURSES_WINDOW_GETBKGRND_METHODDEF \
+ {"getbkgrnd", (PyCFunction)_curses_window_getbkgrnd, METH_NOARGS, _curses_window_getbkgrnd__doc__},
+
+static PyObject *
+_curses_window_getbkgrnd_impl(PyCursesWindowObject *self);
+
+static PyObject *
+_curses_window_getbkgrnd(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ return _curses_window_getbkgrnd_impl((PyCursesWindowObject *)self);
+}
+
+#endif /* defined(HAVE_NCURSESW) */
+
PyDoc_STRVAR(_curses_window_getch__doc__,
"getch([y, x])\n"
"Get a character code from terminal keyboard.\n"
#endif /* defined(HAVE_NCURSESW) */
PyDoc_STRVAR(_curses_window_hline__doc__,
-"hline([y, x,] ch, n, [attr=_curses.A_NORMAL])\n"
+"hline([y, x,] ch, n, [attr])\n"
"Display a horizontal line.\n"
"\n"
" y\n"
PyObject *ch;
int n;
int group_right_1 = 0;
- long attr = A_NORMAL;
+ long attr = 0;
switch (PyTuple_GET_SIZE(args)) {
case 2:
}
PyDoc_STRVAR(_curses_window_insch__doc__,
-"insch([y, x,] ch, [attr=_curses.A_NORMAL])\n"
+"insch([y, x,] ch, [attr])\n"
"Insert a character before the current or specified position.\n"
"\n"
" y\n"
int x = 0;
PyObject *ch;
int group_right_1 = 0;
- long attr = A_NORMAL;
+ long attr = 0;
switch (PyTuple_GET_SIZE(args)) {
case 1:
}
PyDoc_STRVAR(_curses_window_vline__doc__,
-"vline([y, x,] ch, n, [attr=_curses.A_NORMAL])\n"
+"vline([y, x,] ch, n, [attr])\n"
"Display a vertical line.\n"
"\n"
" y\n"
PyObject *ch;
int n;
int group_right_1 = 0;
- long attr = A_NORMAL;
+ long attr = 0;
switch (PyTuple_GET_SIZE(args)) {
case 2:
#define _CURSES_WINDOW_ENCLOSE_METHODDEF
#endif /* !defined(_CURSES_WINDOW_ENCLOSE_METHODDEF) */
+#ifndef _CURSES_WINDOW_IN_WCH_METHODDEF
+ #define _CURSES_WINDOW_IN_WCH_METHODDEF
+#endif /* !defined(_CURSES_WINDOW_IN_WCH_METHODDEF) */
+
+#ifndef _CURSES_WINDOW_GETBKGRND_METHODDEF
+ #define _CURSES_WINDOW_GETBKGRND_METHODDEF
+#endif /* !defined(_CURSES_WINDOW_GETBKGRND_METHODDEF) */
+
#ifndef _CURSES_WINDOW_GET_WCH_METHODDEF
#define _CURSES_WINDOW_GET_WCH_METHODDEF
#endif /* !defined(_CURSES_WINDOW_GET_WCH_METHODDEF) */
#ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
#define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
#endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */
-/*[clinic end generated code: output=3d8d59f44ded2226 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=081cc398989ca202 input=a9049054013a1b77]*/