I am writing an application using ncurses and wish to use box drawing characters in it, specifically u/2550 and u/2551 (as of now). I have for loops setup to draw bars to two sides of the terminal, based off screen size I determine elsewhere.
For whatever reason when it comes to drawing any unicode characters horizontally (here at the bottom of the screen, but it does this on any row), it will go from printing the characters fine to printing garbage 'P's. This is a bit hard to explain, so I have some pictures showing what happens when I draw 6 characters and then 7 or more characters.
The part of the code responsible for drawing these characters is as such, note that the last for loop is what draws these characters, and the iterator is supposed to go farther than just 7, but it does this here and anywhere else.
void drawBorder(){ //draw the border graphics
attron(COLOR_PAIR(3));
for(int i = 1; i < screenSizeY - 1; i++){ //draw left side
mvaddwstr(i, 0, L"║");
}
for(int i = 1; i < screenSizeY - 1; i++){ //draw right side
mvaddwstr(i, screenSizeX - 1, L"\u2551");
}
for(int i = 0; i < 7; i++){ //draw bottom
mvaddwstr(screenSizeY - 1, i, L"\u2550");
}
attroff(COLOR_PAIR(3));
}
I am linking against the ncursesw package and have a properly set locale. Other characters drawn in vertical lines work just fine, but it doesn't here. I am using C++ compiled with g++, running on Linux in an Alacritty terminal session.
This has nothing to do with box draw functions, or specific terminal capabilities, all of the wide characters are perfectly supported by the terminal, and work in other parts of the terminal. This will happen based on how many of these I draw in a row, and also happens for other box characters.
OP sent a more complete example, which shows the problem:
#include <ncurses.h>
#include <string>
#include <iostream>
using namespace std;
int main(){
initscr();
setlocale(LC_ALL, "");
raw();
keypad(stdscr, TRUE);
noecho();
for(int i = 0; i < 10; i++){
mvaddwstr(0, i, L"\u2550");
}
for(int i = 0; i < 6; i++){
mvaddwstr(1, i, L"\u2550");
}
refresh();
getch();
endwin();
return 0;
}
The problem is that the library is initialized with a different locale than is used in the mvaddwstr
calls. The manual page says
The library uses the locale which the calling program has initialized. That is normally done with
setlocale
:
setlocale(LC_ALL, "");
If the locale is not initialized, the library assumes that characters are printable as in ISO-8859-1, to work with certain legacy programs. You should initialize the locale and not rely on specific details of the library when the locale has not been setup.
Because the call to setlocale
is after initscr
, rather than before, ncurses assumes the data is ISO-8859-1, and runs into an unexpected scenario. In other places such as addwstr
, ncurses checks if the data is valid wchar_t
, but in those, it's using the current locale. In this case, it's far away from the functions that it knows must be handled in that way (it's rendering data which has already been processed). The comparison in the library which allow this to be handled using the repeat_char
capability can be improved, but the actual bug is in the sample program.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With