Search code examples
windowswinapiresizedirectxwindow-resize

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


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:

  • contents that seem to walk off the edge of the window and snap back when we slow down or stop dragging
  • contents that seem to pull into the window, intermittently displaced by a border of varying colors, often black or white
  • a seriously ugly "double image" with two overlapping copies of the content displaced by a distance proportional to how much/how fast we are dragging

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:
example 1: jitter

Border:
example 2: border

Another example showing the evil "double image" phenomenon (note the quick flash) from Kenny Liu:

example 2: double-image

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:

  • what are the most likely causes of this kind of ugly jitter/flicker/jumping?
  • how do I tell which cause I am seeing?
  • is this cause specific to particular graphics drivers or general for Windows?
  • how do I fix each cause? can an app fix it?

(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:

  • both native Win32 and managed .NET/WPF/Windows Forms apps
  • both normal Win32 windows and Win32 Dialog windows
  • Windows versions including XP, Vista, 7, 8, and 10 (but see below for the dark truth of multiple causes)

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.


Solution

  • Table of Contents

    Because this is a complex, multi-faceted issue, I recommend reading the answers in this order:

    as 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!