Skip to content

Commit 064a5ad

Browse files
gh-153862: Fix spurious color pair in curses window.inch() on a wide build (GH-154703)
winch() returns the whole code point, so inch() replacing only its low 8 bits left the high bits in the color field. Rebuild from getcchar()'s attributes and color pair. (cherry picked from commit b618874) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7908848 commit 064a5ad

2 files changed

Lines changed: 14 additions & 13 deletions

File tree

Lib/test/test_curses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ def test_read_from_window(self):
517517
with self.subTest(ch=ch):
518518
stdscr.addstr(2, 0, ch)
519519
self.assertEqual(stdscr.instr(2, 0, 1), b)
520-
self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0])
520+
self.assertEqual(stdscr.inch(2, 0), b[0])
521521

522522
def test_coordinate_errors(self):
523523
# Addressing a cell outside the window raises curses.error.

Modules/_cursesmodule.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,10 +1903,10 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1,
19031903
}
19041904

19051905
#ifdef HAVE_NCURSESW
1906-
/* winch() returns the low 8 bits of the character's code point with no locale
1907-
conversion, unlike instr(), so recover the locale byte from the wide cell
1908-
when the character maps to exactly one byte, keeping the attribute and color
1909-
bits in RTN. A character with no single-byte form is left to winch(). */
1906+
/* ncursesw's winch() returns the character's whole code point instead of its
1907+
locale byte, overflowing the chtype's 8-bit character field into the color
1908+
and attribute bits, so rebuild the value from the locale byte plus the
1909+
attributes and color pair reported by getcchar(). */
19101910
static chtype
19111911
curses_cell_locale_byte(chtype rtn, const cchar_t *cell)
19121912
{
@@ -1915,18 +1915,19 @@ curses_cell_locale_byte(chtype rtn, const cchar_t *cell)
19151915
short pair;
19161916
/* getcchar() is not guaranteed to write the text of an empty cell. */
19171917
wstr[0] = L'\0';
1918-
if (getcchar(cell, wstr, &attrs, &pair, NULL) == ERR
1919-
|| wstr[0] == L'\0' || wstr[1] != L'\0')
1920-
{
1918+
if (getcchar(cell, wstr, &attrs, &pair, NULL) == ERR) {
19211919
return rtn;
19221920
}
19231921
/* wctob() mirrors ncurses' own _nc_to_char(): the single-byte form, or EOF
1924-
when the character has none in this locale. */
1925-
int byte = wctob(wstr[0]);
1926-
if (byte != EOF) {
1927-
rtn = (rtn & ~(chtype)A_CHARTEXT) | (unsigned char)byte;
1922+
when the character has none in this locale (then use 0). */
1923+
int byte = 0;
1924+
if (wstr[0] != L'\0' && wstr[1] == L'\0') {
1925+
byte = wctob(wstr[0]);
1926+
if (byte == EOF) {
1927+
byte = 0;
1928+
}
19281929
}
1929-
return rtn;
1930+
return (chtype)byte | (attrs & ~(attr_t)A_COLOR) | COLOR_PAIR(pair);
19301931
}
19311932
#endif
19321933

0 commit comments

Comments
 (0)