Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WinGUI] Unexpected flickering #322

Open
rhaberkorn opened this issue Sep 21, 2024 · 11 comments
Open

[WinGUI] Unexpected flickering #322

rhaberkorn opened this issue Sep 21, 2024 · 11 comments

Comments

@rhaberkorn
Copy link

With WinGUI I observed that drawing commands (e.g. addch()) immediately update the display (GUI window), instead of waiting for refresh() or doupdate(). This causes flickering in some applications that don't expect this behavior.

I have observed this in v4.4.0, as shipped by MSYS, with SciTECO, but there doesn't appear to be any relevant commit ever since.

Is this a known bug? I could construct a test case if necessary.

@Bill-Gray
Copy link
Owner

(Pause to scratch head) Interesting... I'm not surprised I've not observed this; I don't think I have any programs that would have shown it. I assume something like

initscr();
draw some text;
nap a few seconds;
getch();

does the trick? You get a blank screen on other ports until the nap is done (getch() forces a refresh). But on WinGUI, the text is shown right away?

@Bill-Gray
Copy link
Owner

Well, apparently, that's not it. The following test code doesn't show any text until the nap ends, with ncurses, the VT port, or WinGUI. I think I may need that minimal example after all.

Interestingly, with ncurses, the screen isn't even cleared until the nap ends. It looks as if ncurses doesn't adjust the screen at all until the first refresh() occurs.

#include <curses.h>

/* See https://github.com/Bill-Gray/PDCursesMod/issues/322 */

int main( void)
{
   initscr();
   addstr( "Here's some text.  Time for a two-second nap...");
   napms( 2000);
   addstr( "Nap's over.  Hit the any key.");
   getch( );
   endwin();
   return 0;
}

@rhaberkorn
Copy link
Author

Okay, I will have to reduce my main loop until I have a minimal case.

@rhaberkorn
Copy link
Author

Okay, I think I know what's going on. I am using wgetch() after nodelay() in order to poll for CTRL+C. And getch() apparently calls wrefresh(). Can this be disabled?

@rhaberkorn
Copy link
Author

rhaberkorn commented Sep 21, 2024

Another source of flickering:

int main(void)
{
	initscr();

	for (int i = 0; i < 1000; i++) {
		mvaddstr(1, 1, "Hello world XXX");
		refresh();
		napms(200);
	}

	getch();
	endwin();
	return 0;
}

At least on Windows 2008 I can see the "X" flickering. But it doesn't happen under Wine.

@Bill-Gray
Copy link
Owner

I've got a guess on that last, which may (or may not) lead to thoughts on the problem in general.

This example doesn't actually change anything within the loop. On the first iteration, the text 'Hello world XXX' will be drawn; on the remaining 999, refresh() will look through the screen, see that nothing has changed, and draw absolutely nothing.

However, the cursor will blink. Because Windows has somewhat... unfortunate handling of text drawing, when we draw "new" text, we redraw the previous character, even if it hasn't changed and (a few lines earlier) similarly redraw the following character. Otherwise, we get some garbage left on the screen.

So when the cursor blinks, the preceding character (X) blinks, as does the following one (space, so you don't actually see anything).

Exactly why Windows flickers, though, is a puzzler. That redraw should push exactly the same pixels (for the X) as before.

@Bill-Gray
Copy link
Owner

(A warning : I don't expect to get back to PDCursesMod for a day or so after this post. Figured I'd best get this posted while still fresh in my mind, though...)

I am pretty sure that wgetch( win) is supposed to refresh win (i.e., "it's not a bug, it's a feature"). I do see that the ncurses documentation for wgetch() says

o   If the window win has been moved or modified since the last call to
           wrefresh(3x), curses calls wrefresh on it.

I'd always expected a refresh() to accompany every getch(), without exceptions. However, it's suggested a few lines before the text quoted above that the auto-refresh should only happen in echo mode.

But I've tried it with the following code. Run it with no command-line arguments, and it uses echo mode; add an argument, and it uses noecho. In both cases, ncurses refreshes at each getch(). As best I can tell, there's no way to avoid a refresh at each getch().

#include <curses.h>

int main( const int argc, const char **argv)
{
   int i = 0;

   initscr();
   nodelay( stdscr, TRUE);
   if( argc == 1)
      echo( );
   else
      noecho( );
   while( ERR == getch( )) {
      mvprintw(1, 1, "Hello world %d", i++);
      napms(200);
      mvprintw(2, 1, "Hello world %d", i++);
      napms(200);
      mvprintw(3, 1, "Hello world %d", i++);
      napms(200);
   }

   endwin();
   return 0;
}

@rhaberkorn
Copy link
Author

rhaberkorn commented Sep 22, 2024

Thanks for taking the time to investigate my questions!

Exactly why Windows flickers, though, is a puzzler. That redraw should push exactly the same pixels (for the X) as before.

But you can reproduce it?

As best I can tell, there's no way to avoid a refresh at each getch().

What I can and will do of course is to create a newpad(1, 1) and wgetch() on it. In the code there is an exception for pads, which is logical since they cannot be wrefreshed.

rhaberkorn added a commit to rhaberkorn/sciteco that referenced this issue Sep 22, 2024
* This is especially important on platforms, requiring the wgetch()
  poll workaround to detect CTRL+C (PDCurses/WinGUI).
  wgetch(cmdline_window) would implicitly wrefresh(cmdline_window),
  which resulted in additional flickering when pressing function keys.
  This is no longer so important since key macros are processed
  as an unity and the cmdline will be updated only after processing
  all of the characters contained in them, ie. only once after the key press.
  Still, there could have still been unwanted side effects.
  At the very least, wgetch(input_pad) should be faster.
* The XTerm clipboard implementation was getch()ing on stdscr,
  so potentially suffered from the same problem.
  It should be tested again.
* Since keypad() is now always enabled even on netbsd-curses.
  I assume that the function key processing bug in netbsd-curses
  has been fixed by now. We are not building any releases with
  netbsd-curses. But it should be retested.
* It does not resolve all flickering issues on PDCurses/WinGUI.
  Both the command line and the Scintilla view still flicker near
  the cursor. See
  Bill-Gray/PDCursesMod#322
@rhaberkorn
Copy link
Author

At least on Windows 2008 I can see the "X" flickering.

It does indeed appear as if the flickering is happening only ever near the cursor.

@Bill-Gray
Copy link
Owner

Possible fix here : I'm beginning to wonder if this business of refreshing the preceding and following character is really needed. The code in question (lines 396-397 for the trailing character, 401-406 for the preceding) was added before this project moved to GitHub, i.e., before 2016. So I don't have documentation of what the garbage pixel problems were.

But I've just tried removing those seven lines, and everything appears to still work. I'd give that a try and see what happens.

@rhaberkorn rhaberkorn changed the title [WinGUI] Updates screen immediately, instead of waiting for doupdate() [WinGUI] Unexpected flickering Sep 27, 2024
@rhaberkorn
Copy link
Author

I changed the issue's title, so that readers aren't lead to believe, there's a bug, where there is none.

Bill-Gray added a commit that referenced this issue Oct 3, 2024
… trailing character is really needed to avoid stray pixel garbage. In fact, I can't see how that could possibly have ever worked. It caused some (not all) of the flickering problem described in issue #322.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants