Как пара цветов фона должна влиять на цвет последующих символов в ncurses?
Я смог воспроизвести свою проблему с помощью этого небольшого примера кода:
#include <ncurses.h>
int main() {
initscr();
start_color();
init_pair ( 1, COLOR_BLUE, COLOR_BLACK );
init_pair ( 2, COLOR_YELLOW, COLOR_BLACK );
bkgd ( (chtype) COLOR_PAIR(1) );
attrset(COLOR_PAIR(2));
printw("NO WAR!");
refresh();
getch();
endwin();
return 0;
}
После компиляции с
Я изучаю код игры, написанной на C и использующей ncurses. Код инициирует пары цветов, а затем устанавливает пару цветов в качестве фона. Моя проблема в том, что когда я делаю игру из исходного кода, дальнейшее поведение отличается в зависимости от того, (1) я собираю код как обычно в Debian или Fedora или (2) я собираю код с расширением . Как правило, дальнейшая настройка цвета символов работает должным образом, и я получаю фон, перезаписанный цветными символами в местах, где символы появляются на экране. Но если я создам его с помощью , все последующие символы будут отрисованы той же цветовой парой, которой был назначен фон. (Я могу изменить эту пару цветов, и это повлияет на все.)
Если я удалю часть, которая устанавливает пару цветов фона, программы будут работать должным образом в обоих случаях: пара цветов по умолчанию выглядит как белая на черном, а дополнительные символы окрашены в соответствии с кодом.
Я прокомментировал строку ниже, удаление которой помогает.
/* set up colors */
(void) start_color();
if ( has_colors() && ( COLOR_PAIRS > 7 ) ) {
state.options |= OPTION_HAS_COLOR;
(void) init_pair ( 1, COLOR_GREEN, COLOR_BLACK );
(void) init_pair ( 2, COLOR_RED , COLOR_BLACK );
(void) init_pair ( 3, COLOR_YELLOW, COLOR_BLACK );
(void) init_pair ( 4, COLOR_BLUE, COLOR_BLACK );
(void) init_pair ( 5, COLOR_MAGENTA, COLOR_BLACK );
(void) init_pair ( 6, COLOR_CYAN, COLOR_BLACK );
(void) init_pair ( 7, COLOR_WHITE, COLOR_BLACK );
/* Removing the following line helps */
(void) bkgd ( (chtype) COLOR_PAIR(WHITE) );
state.items[ROBOT].color = WHITE;
state.items[KITTEN].color = randcolor();
for ( i = BOGUS; i < state.num_items; i++ ) {
state.items[i].color = randcolor();
}
} else {
state.options &= ~ OPTION_HAS_COLOR;
}
}
/*@-globstate@*/
static void draw ( const screen_object *o ) {
attr_t new;
/*@-nullpass@*/
assert ( curscr != NULL);
if ( ( state.options & OPTION_HAS_COLOR ) != 0 ) {
new = COLOR_PAIR(o->color);
if ( o->bold ) { new |= A_BOLD; }
if ( o->reverse ) { new |= A_REVERSE; }
(void) attrset ( new );
}
(void) addch ( o->character );
/*@+nullpass@*/
}
Полный исходный код C: https://github.com/robotfindskitten/robotfindskitten/blob/main/src/robotfindskitten.c
Я пробовал собирать с версиями 6.2.20200212 и 6.2.20210619. Версии в Debian, с которыми я пытался работать, были 6.2+20201114-2 и 6.3-2. Версия для Fedora — 6.2.20210508.
Разница, похоже, не вызвана переменными среды, поскольку я могу воспроизвести результат в том же терминале на Debian, имея локально скомпилированный, репозиторий и версии одного и того же пакета. Кроме того, я могу изменить пару цветов фона, изменив исходный код, чтобы терминал правильно определялся как поддерживающий цвет.
Согласно страницам руководства (
- Библиотека сначала сравнивает символ, и если он совпадает с частью фона текущего символа, она заменяет его новым фоновым персонажем.
- Затем библиотека проверяет, использует ли ячейка цвет, т. е. имеет ли ее значение пары цветов ненулевое значение. Если нет, то он просто заменяет атрибуты и пару цветов в ячейке на те, что из нового фонового символа.
- Если ячейка использует цвет, и он соответствует цвету текущего фона, библиотека удаляет атрибуты, которые могли исходить от текущего фона, и добавляет атрибуты из нового фона. Он заканчивается установкой ячейки для использования цвета нового фона.
- Если в ячейке используется цвет, который не соответствует цвету текущего фона, библиотека обновляет только нецветовые атрибуты, сначала удаляя те, которые могли исходить от текущего фона, а затем добавляя атрибуты из нового фона.
Я так понимаю, что по какой-то причине в
Что может повлиять на настройку цвета символов? Это ошибка в библиотеке или вариант реализации? Удаление
1 ответ
После звонка
bkgd
, последующие вызовы для использования цвета фона, если только
waddch
позвонить (или
wattrset
) указал цвет. Это сделано вrender_char
функция ncurses:
static NCURSES_INLINE NCURSES_CH_T
render_char(WINDOW *win, NCURSES_CH_T ch)
/* compute a rendition of the given char correct for the current context */
{
attr_t a = WINDOW_ATTRS(win);
int pair = GetPair(ch);
if (ISBLANK(ch)
&& AttrOf(ch) == A_NORMAL
&& pair == 0) {
/* color/pair in attrs has precedence over bkgrnd */
ch = win->_nc_bkgd;
SetAttr(ch, a | AttrOf(win->_nc_bkgd));
if ((pair = GET_WINDOW_PAIR(win)) == 0)
pair = GetPair(win->_nc_bkgd);
SetPair(ch, pair);
} else {
/* color in attrs has precedence over bkgrnd */
a |= AttrOf(win->_nc_bkgd) & COLOR_MASK(a);
/* color in ch has precedence */
if (pair == 0) {
if ((pair = GET_WINDOW_PAIR(win)) == 0)
pair = GetPair(win->_nc_bkgd);
}
AddAttr(ch, (a & COLOR_MASK(AttrOf(ch))));
SetPair(ch, pair);
}
TR(TRACE_VIRTPUT,
("render_char bkg %s (%d), attrs %s (%d) -> ch %s (%d)",
_tracech_t2(1, CHREF(win->_nc_bkgd)),
GetPair(win->_nc_bkgd),
_traceattr(WINDOW_ATTRS(win)),
GET_WINDOW_PAIR(win),
_tracech_t2(3, CHREF(ch)),
GetPair(ch)));
return (ch);
}
Однако в ncurses 6.2 была ошибка, как обсуждалось в списке рассылки в марте 2020 года , о чем сообщалось в guix 2.0. Был простой обходной путь для вызывающих абонентов (который может повлиять на некоторых пользователей). Версия guix не указана в вопросе.