Flickering ACS_CKBOARD using ncurses in rxvt - c

I wanted to get familiar with the curses interface (never used it before), so I wrote a little snake game last weekend. There's a one-line status WINDOW * and the rest of the screen is the field WINDOW * The game logic calls a central drawing function to put an item, only when necessary:
/* note: CP_* are just enum values to give my own color pairs names */
void
screen_putItem(Screen *self, int y, int x, Item item, int refresh)
{
switch (item)
{
case EMPTY:
mvwaddch(self->field, y, x, ' '|COLOR_PAIR(CP_WHITE));
break;
case HEAD:
#ifdef WIN32
/* 'smiley' character for windows console */
mvwaddch(self->field, y, x,
1|COLOR_PAIR(CP_YELLOW)|A_BOLD|A_ALTCHARSET);
#else
mvwaddch(self->field, y, x, '#'|COLOR_PAIR(CP_YELLOW)|A_BOLD);
#endif
break;
case TAIL:
mvwaddch(self->field, y, x, ACS_CKBOARD|COLOR_PAIR(CP_YELLOW));
break;
case FOOD:
mvwaddch(self->field, y, x, '#'|COLOR_PAIR(CP_GREEN)|A_BOLD);
break;
case FFOOD:
mvwaddch(self->field, y, x, '#'|COLOR_PAIR(CP_GREEN));
break;
case WALL:
mvwaddch(self->field, y, x,
' '|COLOR_PAIR(CP_RED)|A_REVERSE);
break;
}
if (refresh) wrefresh(self->field);
}
Problem is: in rxvt, the body of the snake (made from TAIL items) is sometimes flickering. It is not redrawn on snake movement, only the last position of the head is replaced by a TAIL and the tail item at the end of the snake is replaced by an EMPTY.
For your reference, the whole project is on github, see the revision at time of asking this question.
For input, the code uses getch() and I already checked this isn't the problem (it shouldn't be, stdscr is refreshed at init and never touched again) by using only wgetch() on the field window with the same result.
Also, it works fine (flicker-free) in good old xterm and in the windows console, using pdcurses. It works fine in rxvt iff I replace the ACS_CKBOARD in the snippet above with some "ordinary" character.
So, now I'd like to know: Did I encounter a bug/shortcoming in rxvt? Is there something special about the ACS_* characters that could cause a terminal to flicker? Is there anything just wrong with my approach?

Tracing shows me that your program does almost all wgetch's from stdscr, but almost all refresh's are done against the second window created (looks like the first is just a status line).
ncurses' trace feature is normally in a debug-library; the copies that I compile for myself have it compiled in normally.

Related

Query cursor position with GTK

Is there a way to query the cursor position using the GTK C libraries? I am writing a program where I need to read out the position of the cursor in real time (either through a callback function or by polling the values to look for change). I have scanned through the GTK documentation, but I couldn't find anything obvious that exposes the cursor position.
I am currently writing this program using the GTK C libraries because a) I already have some code written in C to interface with the low level Raspberry Pi peripherals, and I'd rather not rewrite it for a different language if I can avoid it. The low level code is based on mmap(), which I believe still works with C++, so if push comes to shove, I supposed I can rewrite it in C++ with some other GUI library like wxWidgets or QT. (Are there easy ways to read the cursor position with those libraries?)
You can take a look at how it's done in those toy widgets which draw eyes on the panel, e.g. xfce4-eyes-plugin.
gboolean
where (void)
{
gint x, y;
GdkWindow *window;
GdkDevice *mouse_device;
#if GTK_CHECK_VERSION (3,20,0)
GdkSeat *seat = gdk_display_get_default_seat (gdk_display_get_default ());
mouse_device = gdk_seat_get_pointer (seat);
#else
GdkDeviceManager *devman = gdk_display_get_device_manager (gdk_display_get_default ());
mouse_device = gdk_device_manager_get_client_pointer (devman);
#endif
window = gdk_display_get_default_group (gdk_display_get_default ());
gdk_window_get_device_position (window, mouse_device, &x, &y, NULL);
g_message ("pointer: %i %i", x, y);
return G_SOURCE_CONTINUE;
}

How to use the move function under curses.h

It doesn't print at coordinates y=10, x=20.
#include <stdio.h>
#include <curses.h>
int main()
{
initscr();
refresh();
WINDOW *win;
wmove(win, 10, 20);
refresh();
printf("hi\n");
return 0;
}
When I execute it like this...
./a.out > op_file
This is what is op_file
[?1049h[1;24r(B[m[4l[?7h[H[2J-1
hi
Can someone explain...??
You must use initscr() function to initialize the screen and endwin() at the end to close the window...
If you move(), you must use refresh() or the cursor won't move physically.
To move the cursor to a new position on a window, use the function int wmove(WINDOW *win, int y, int x)
wmove(win, y, x);
where (x, y) are the coordinates of the new position in the window. If the window has nlines lines and ncolumns columns, then
0 <= y < nlines
0 <= x < ncolumns
Refresh. The actual cursor motion is not shown on the screen untill you do a wrefresh(win).
move(y, x) is equivalent to the wmove(stdscr, y, x).`
The move() and wmove() functions move the cursor associated with the current or specified window to (y, x) relative to the window's origin. This function does not move the terminal's cursor until the next refresh operation.
To move the logical cursor in the user-defined window my_window to the coordinates y = 5, x = 10, use :
#include <stdio.h>
#include <curses.h>
int main(){
refresh();//First refresh
WINDOW *my_window;
int a = wmove(my_window, 5, 10);
refresh();////Second refresh
printf("%d\n",a);
printf("hi\n");
return 0;
}
The output
[?1049h[1;24r(B[m[4l[?7h[H[2J-1
hi
shows the printable characters written. If you look at the complete text, e.g., in a text-editor, there'll be ASCII escape characters before the [ and ( characters since that's part of the escape sequence.
Your example doesn't show cursor movement (aside from the home position which you'd see as ^[[H near the end) because there's no reason for the curses library to actually move the cursor. If you had asked it to read a character, e.g., using getch, it would have to stop and decide where the cursor should be — and your wmove would do that — except that win is not initialized. The simplest thing to do is use stdscr (which is initialized by initscr).
The program quits curses calls without doing an endwin (which leaves the terminal in raw mode). The data does get written to the screen with the refresh call. The data written with printf happens to come out in the right order, but that's only coincidental since it does not use the same output buffering as ncurses.
Both of the other answers contain similar errors.
This works.
#include <stdio.h>
#include <curses.h>
int main()
{
initscr();
refresh();
WINDOW *win;
win = stdscr;
wmove(win, 10, 10);
refresh();
printf("hi\n");
return 0;
}
Thanks to #interjay.

Ncurses "mvaddch()" Moves Diagonal

I'm trying to create an Etch-n-sketch game and when I move the arrow keys up and down, the cursor moves to the right and in what ever direction I pressed. I can move right, though it appears to be skipping a spot and I cant move left
Code for moving and drawing:
void moveCursor(char input)
{
int cursorX_Pos;
int cursorY_Pos;
int arrows;
getyx(stdscr, cursorY_Pos, cursorX_Pos);
arrows = 1;
switch(input)
{
case UP:
cursorY_Pos--;
arrows = 0;
break;
case DOWN:
cursorY_Pos++;
arrows = 0;
break;
case RIGHT:
cursorX_Pos++;
arrows = 0;
break;
case LEFT:
cursorX_Pos--;
arrows = 0;
break;
default:
arrows = 1;
break;
}
if (arrows == 0)
{
draw(cursorY_Pos,cursorX_Pos);
}
}
void draw(int y, int x)
{
mvaddch(y, x, '#');
refresh();
}
I'm not really sure where the code is trying to move diagonal. I tried splitting up the mvaddch into move and addch. I tried them at diffrent times and the move works (doesnt appear to be skipping) but when I enable the addch part, it skips and goes diagonal. How do I do fix this?
When you add a character to the screen, the cursor moves to the position after it. So, when you then fetch the current cursor position, it's one cell to the right of where you moved to, before adding the character. Thus, when trying to move left, for instance: you're subtracting 1 in moveCursor(), and adding 1 back in draw().
Either subtract 1 from cursorX_pos after the getyx(), or perhaps, maintain your coordinate values independent of curses' idea of where the cursor is (i.e. just leave out the getyx()).
For bonus points, realize that the target coordinates (for the next draw) and the current position are two different things, and optimize accordingly. (Hint: moving right shouldn't require a move() at all.)

C - Ncurses - How to stop cursor from moving over walls (walls made up of a bunch of charecters)

Is there a way or function available which would stop me from going over the characters. The maze looks like the following below. I actually dont use printf, but mvprint. I just used printf as an example below.
printf("xxxxxx x");
printf("xxxxxx x");
printf("xxxxxx x");
printf("x x");
printf("x xxxxxx");
printf("x xxxxxx");
I tried the this code below but it doesn't seem to work. The cursor still goes over the x characters. In the third line of the code you can see I've said that if there is a character 'f' there which is created by the bunch of printf statements seen above, the cursor shouldn't move. This doesn't seem to work.
if(m == 's')
{
if((oldy+1,x)=='x') // This is the part of the code where i say that if the next spot is an 'x' dont move.
{
mvprint(win, 10,0,"Sorry, you cant move there.");
refresh(win);
}
else
{
move((y= oldy+1),x);
refresh();
oldy = y;
}
}
After a little bit of research, I think you want your inner condition to be:
if(mvinch(oldy+1,x) == 'x')
The mvinch(y,x) function moves and returns the character at that location.
Also, as other people mentioned, mixing standard I/O and Curses is unreliable at best. When I tried something like this on my machine to test, my program told me that the entire screen was made up of spaces.

ncurses write to window not displayed

I've got one function do_refresh which should draw some character in a window like this:
void do_refresh(WINDOW *w_game, int *xPos, int *yPos, char vector[], snake *snake){
mvwaddch(w_game, (*yPos), (*xPos), snake->headsym);// mv to new pos and place char
wrefresh(w_game);
}
The window w_game has also a panel pendant which lies on top of all other panels.
Before that function gets called, I let the user do non blocking input with getch() and timeout(0):
fflush(stdin);
key = getch();
if(key != ERR){ ...
only the first time I call do_refresh, the char gets drawn to the window, later nothing changes though xPos & yPos as well as all other parameters to mvwaddch are valid and change over the time.
Doing a redrawwin on the window causes a segfault, using wgetch(w_game) instead of getch() returns no input.
I would be very grateful if someone could at least link to a decent documentation what has to be considered when using wgetch instead and what it does different.
UPDATE
I found the solution to the problem, The function which sets up the panel stuff modifies the address of the windows!, you have to return the (new) destination of the pointer to main and reset it there like this:
...setup_panels(...){
return w_game; // my window
}
int main(...){
WINDOW *w_game;
[...]
w_game = setup_panels(...);
}

Resources