Flickering on window when resizing from left side
Asked Answered
E

2

4

It seems that my window is flickering whenever I move and window and resize at the same time. This usually occurs when sizing is done from the left side of the window.

Why does this flickering happen? In other words, what is the OS doing when you reposition a window?

Note: I do not experience flickering when resizing from the right side which means the window is not necessarily moving its origin X and Y.

Electroscope answered 6/1, 2014 at 20:21 Comment(3)
The reason is because you're moving the entire window. Windows is going to now redraw everything at that specific position. Shrinking from the right side only makes it repaint its borders. The client area does not need repainting as it's just cropped. Stretching from the right requires that whatever controls wasn't painted will now be drawn as well as the client area. Moving a window requires repainting every single component and the client area as well as its borders.Soulier
@CantChooseUsernames I am trying to connect what you said to this SWP_NOCOPYBITS. But I thought it just copies the bits over.Electroscope
What OS are you using? Windows XP with themes enabled (i.e. by default) has unavoidable flicker. All other versions of Windows except Vista are OK. I haven't tried Vista.Caralie
S
5

Resizing a window under Windows involves several messages sent between the OS and the window's handler (the lpfnWndProc member of WNDCLASSEX structure used to register the window's class). You can discover them by yourself using some message monitoring tool. Spy++ that comes with Visual Studio is one such tool.

One interesting message is WM_NCCALCSIZE: this message, called during window resizing, can generate two rectangles (when WVR_VALIDRECTS flag is set): source and target specifying what content of the old window's client area can be "reused" at the new window's position. By default it's assumed that the top-left corner is a pivot:

  • resizing the left or top border causes the old window's content to get copied to preserve the pivot;
  • resizing the right ot bottom border copies nothing because the top-left corner of the window did not move.

This default copying can cause flicker, if it does not correspond to the way you position visuals during repaint. For example, everything that is displayed relative to the right or bottom border will be misplaced after resize from the left or top border: these objects will get moved unnecessarily leaving strange mix of old and new things after such resize, because only non-copied pixels will be repainted. If you try to cure the mess with InvalidateRect during, say, WM_SIZE you will get the flicker (the time interval where things are misplaced is very short but it still exists).

The easiest way to disable this behavior is by setting the CS_HREDRAW and CS_VREDRAW Class Styles for your window.

Streeto answered 6/1, 2014 at 21:31 Comment(5)
Great answer! To follow up, does the OS stretch the contents of the old when it attempts to preserve the pivot when resizing from top and left? Additionally, it seems like OS is also doing moving first and then resizing it. Can you confirm? Also, I have disabled CS_HREDRAW and CS_VREDRAW and still face flickering.Electroscope
And how can we stop setPosWindow from calling WM_PAINT?Electroscope
The OS does not stretch: it copies using the shorter of the source and target client area width/height. Another reason for flickering can be due to initializing WNDCLASSEX::hbrBackground to valid brush: WM_ERASEBKGND uses it to clear the remaining area before you get chance at repainting in WM_PAINT.Streeto
SetWindowPos has the flag SWP_NOREDRAW that should prevent the generation of WM_PAINT and related redrawing messages. You'll then need to ensure consistent view either by calling InvalidateRect or drawing directly to the window (with GetDC or similar).Streeto
This answer gave maybe the right theory, but it gave a wrong solution. Setting CS_HREDRAW|CS_VREDRAW will not stop the window from flickering when you size it via the left border. Also NonNumeric's suggestion is wrong, avoiding using an hbrBackground brush or returning true from WM_ERASEBKGRND will not stop the problem.Sorrento
N
0

A 2018 update.

The WM_NCCALCSIZE WVR_VALIDRECTS trick is still a good way from preventing Windows XP/Vista/7 SetWindowPos from doing a needless BitBlt that causes the flickering.

However, Microsoft did it again and on Windows 8/10, the DWM window manager adds another layer of BitBlt on top of the legacy SetWindowPos BitBlt which can cause the same problem and is harder to work around.

For an explanation of why the unwanted BitBlt causes flickering, as well as sample code of the WM_NCCALCSIZE WVR_VALIDRECTS trick and some code ideas for how to prevent Windows 8/10 Aero from doing the same, please see:

How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?

Nkrumah answered 26/10, 2018 at 8:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.