THE PROBLEM: When I grab the resize border of my Windows app, especially the top or left borders, and resize the window, the contents of the window do resize "live" as I drag, but they resize in a hideous manner that looks like a blatant bug to even the most novice user: the contents at the opposite edge of the window from the edge I am dragging jitter/flicker/jump back and forth wildly. Depending on the situation, the phenomenon may look like:
The ugly phenomenon stops as soon as I stop dragging, but during the dragging it makes the app look amateurish and unprofessional.
It is not an understatement to say this Windows problem has driven thousands of app developers crazy.
Here are two example pictures of the phenomenon, kindly prepared for a related question by Roman Starkov:
Jitter:
Border:
Another example showing the evil "double image" phenomenon (note the quick flash) from Kenny Liu:
Another example video of the phenomenon with Task Manager is here.
THE QUESTION: Any developer who has experienced this problem quickly finds that there are at least 30 Stack Overflow questions, some recent and some dating from 2008, full of promising-sounding answers that rarely work. The reality is that this one problem has many causes, and the existing Stack Overflow questions/answers never make the wider context clear. This question seeks to answer:
(This is meant as a canonical Q&A to explain all the different causes of window resize jitter so that users can identify which of the causes is causing their problem and solve it. As the answers explain, all the permutations above (native/managed, window/dialog, XP-10) boil down to only two root causes, but identifying which you have is the tricky part.)
SCOPE OF THIS QUESTION: For the scope of this question, the phenomenon happens with:
NOT IN SCOPE OF THIS QUESTION:
If your app has one or more child windows (child HWNDs), the info in this question is useful to you (since the jerk-causing BitBlts
we will describe are applied to your child windows along with the parent window), but during window resize you have an additional problem to handle that is beyond the scope of this question: you need to make all your child windows move atomically and in sync with the parent window. For this task, you will probably want BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos
and you can find out about them here and here.
This question assumes that if your app draws to a window using GDI, DirectX, or OpenGL, then you have already implemented a WM_ERASEBKGND
handler in your wndproc
that simply returns 1. WM_ERASEBKGND
is an arcane Windows remnant from Windows 3.1 that comes before WM_PAINT
to give your app a chance to "erase the background" of your window before you draw your window...uh huh. If you let the WM_ERASEBKGND
message go into DefWindowProc()
, that will cause your entire window to get painted a solid color, usually white, on each redraw, including redraws that happen during live window resizing. The result is an ugly full-window flicker that is gross, but not the type of jitter/flicker/jumping we are talking about in this question. Intercepting WM_ERASEBKGND
fixes this problem immediately.
This question is primarily about live-resize by dragging window borders with the mouse. However, much of what is written here also applies to ugly artifacts you can see when an app manually does a one-time window resize using SetWindowPos()
. These are less visible though because they only flick on the screen for one instant, rather than over a long period of dragging.
This question is not about how to make your app-specific drawing code go faster, even though doing so may be a solution to the ugly resizing problem in many cases. If your app really does take huge amounts of time to redisplay its contents during live window resize, consider optimizing your drawing code in general or at least switching to a faster, lower-quality drawing mode during resize by intercepting the WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE
messages to detect resize.
If your app fails to resize at all during app resizing (e.g. it "hangs" during resizing, especially if it is OpenGL using GLFW or other library), see these other questions which explain about Microsoft's hideous nested/modal event loop inside WM_SYSCOMMAND
during dragging: here especially this good answer, here, here, here, and here.
If you're using the top or left border, your client area contents will move along with the top left of the client area. In order to get any live resizing when shrinking the window, you have to manually draw from a wndproc message like WM_SIZE, or call InvalidateWindow () to trigger a later WM_PAINT.
There is a second hack, and it is an incredibly creative one: as explained in the StackOverflow post Can't get rid of jitter while dragging the left border of a window, you can actually create two main windows in your app, and every time Windows would do SetWindowPos, you intecept that and instead hide one window and show the other!
If your app really does take huge amounts of time to redisplay its contents during live window resize, consider optimizing your drawing code in general or at least switching to a faster, lower-quality drawing mode during resize by intercepting the WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE messages to detect resize.
So, most solutions for fixing resize problems involve disabling the BitBlt. If you implement a WM_NCCALCSIZE handler and that handler returns WVR_VALIDRECTS when wParam is 1, you can actually control which pixels Windows copies ( BitBlts) from the old client area and where Windows places those pixels in the new client area.
You might be able to glean ideas I missed by looking over the source material:
2014 with 2017 updates: Can't get rid of jitter while dragging the left border of a window : probably the most up-to-date question but still lacks context; suggests a creative but rather crazy hack of having two windows and alternately unhiding them during live resize! Also the only question I have found with an answer mentioning a race condition in DWM and a partial timing fix with DwmGetCompositionTimingInfo()
.
2014 Why is there a black lag every time a WPF window is resized? : yes WPF does it too. No useful answers
2009 How to fix the WPF form resize - controls lagging behind and black background? : controls lagging behind and black background?" multi-HWND example. mentions WM_ERASEBKGND
and background brush tricks, but no modern answer.
2018 Is there a way to reduce or prevent form flickering when using WPF? : yes, still not fixed as of 2018.
2018 Reduce flickering when using SetWindowPos to change the left edge of a window
: unanswered question that got many obsolete recommendations like WM_NCCALCSIZE
2012 OpenGL flickering/damaged with window resize and DWM active : good statement of problem, answerers completely misunderstood the context and provided inapplicable answers.
2012 How to avoid transient updates in a GUI resize? : mentions the trick of intercepting WM_WINDOWPOSCHANGING
and setting WINDOWPOS.flags |= SWP_NOCOPYBITS
.
2016 Unity bug report: "Window resizing is very choppy and stutters (border does not smoothly follow the mouse)" typical bug report found in hundreds of apps that is partially due to the problem in this bug report, and partially due to certain apps having slow drawing. The only doc I EVER found which actually says that Windows 10 DWM clamps and extends the outer pixel of the old window, which I can confirm.
2014 Flickering on window when resizing from left side with pre-Windows-8 answer including CS_HREDRAW/CS_VREDRAW
and WM_NCCALCSIZE
.
2013 Resizing Window causes smearing near the right border with old-school Win-7-only solution to disable Aero.
2018 Flicker-free expansion (resize) of a window to the left an example of a multi-window (multi-HWND) case, no real answer.
2013 WinAPI C++: Reprogramming Window Resize : too ambiguously asked to tell whether it is about client-area flickering (like this question) or non-client-area flickering.
2018 GLFW bug "Resizing windows on Windows 10 shows jumpy behaviour" one of MANY such bugs which never explain the context, like many StackOverflow posts
2008 "Flicker Free Main Frame Resizing" CodeProject that actually does a StretchBlt but won't work in a Windows 8+ world, where app does not have control when incorrect pixels are shown on screen.
2014 Smooth window resizing in Windows (using Direct2D 1.1)? : Well-stated but unanswered issue with Windows 8+ DWM copy
2010 How do I force windows NOT to redraw anything in my dialog when the user is resizing my dialog? : WM_NCCALCSIZE fix to disable bitblt that no longer works in Windows 8+ since DWM corrupts the screen before app has chance to display.
2014 Flicker when moving/resizing window : roundup of previous fixes that do not work in Windows 8+.
2007 WinXP-era "reducing flicker" CodeProject recommending WM_ERASEBKGND+SWP_NOCOPYBITS
2008 early Google Bug report of new Vista DWM problems
Because this is a complex, multi-faceted issue, I recommend reading the answers in this order:
PART 1: What Makes Resize Look Good or Bad?
PART 2: Identifying and Fixing Windows Resize Problems
SetWindowPos()
BitBlt
and Background Fillas well as a list of source material which may help others glean insights:
Please feel free to contribute more answers with creative ways of avoiding the problems described in 2a and especially 2b!
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