Reputation: 31
As of 26 March 2015, problem solved, see bottom of this page, a very dirty trick.
As of 18 Aug 2014, partly solved: DWM is the culprit (see the last comment).
I've built my own window style using win32 API's. Everything went fine under windows XP and Windows 7. However, under windows 8 weird things happen: Dragging the left border of the window causes extreme jitter at the right side, while it shouldn't move at all. Take a look at this and you will understand what I mean.
When I drag the right border, the left side doesn't move as it should be. Admittedly, there is some flickering, but that's acceptable. See this
I've tried SetWindowPos()
and (begin/End)DeferWindowPos
with several flags, but to no avail. Even with SWP_NOREDRAW
and blocking all other paintings doesn't help. Neither with or without CS_HREDRAW
and CS_VREDRAW
.
Of course I'm using double buffering. Yet It seems impossible to get rid of that pesky jitter. I've also tried another driver for the Intel HD 4000 graphic engine, again to no avail. Do I overlook something? Is it a bug of Windows 8?
By the way, when I switch on the "Show window contents while dragging" option (in the Advanced system settings menu), all other applications show the same behavior.
Any help will be greatly appreciated.
Cheers, Edmond.
PS: Disabling "Show window contents while dragging" is no option, because it's built in feature of my application.
Edit1: It seems that d7samurai is struggling with the same problem.
Follow up: I've tried a lot of things to get rid of the jitter, but nothing helps. The problem is that W8 simply doesn't do what it should do. Take for example the SWP_NOREDRAW
flag. As expected, repainting of the window side that has been moved, is suppressed, So far so good. BUT.... the other side (of the window), which is still valid, this one gets repainted! It's not only totally needless and useless, but it is repainted with jitter! Moreover, painting is two times slower compared with W7 and XP. After spending a whole week on this problem, I'm through with W8, totally! It's really a POC and the guys who are responsible for this botch job are mentally deranged. I really hope that W9 will do a better job. Amen.
THOU SHALT JITTER:
It appeared that the anomalies described above are not limited to only W8. Also W7 showed the same behavior when it is set to "best appearance" or at least to "Enable desktop composition" together with "Use visual styles on windows and buttons". I then thought it might be possible to fool windows by not using the SetWindowPos function at all, rather by sending a ShowWindow( hWnd, SW_MAXIMIZE )
command and intercepting the WM_GETMINMAXINFO
msg where I specify the desired size and position. Guess what? I still got jitter. Arghhh !!!
What to do next? Is there any possibility to intercept the painting at a lower/deeper level (hooks?) in order to redraw a window in a decent way?
Update dd 03-26-2015, a very dirty trick:
Eureka! I finally found the solution to the problem. But first, let me explain what is happening and why dragging is accompanied with jitter. Suppose you want to expand the left side of a window. Contrary to expanding the right side, this is done in two steps. First, the content of the window with its original size is moved to the left. After this has been done, the content is expanded to such an extent that the new right side coincides with the previous right side. In short it's combination of a "move" followed by a "resize" and this is what causes the ugly jitter. Similar things happen when you are dragging the top of a window. In Windows 8.1 or 10, there is nothing you can do against it. I've also tried the new DWM functions (BufferedPaintInit
, BeginBufferedPaint
, EndBufferedPaint
, BufferedPaintUnInit
) regrettably, to no avail. Also SetWindowPlacement()
produces jitter. Apparently, all these functions lead to the same culprit which spoils a resize.
I then reasoned that when you create a new window and display it with a new size, it doesn't jitter at all. Rather obvious, I would say. So repeatedly creating a new window and subsequently destroying the previous one, might be a solution, but this isn't very efficient, of course. While playing with this idea, I discovered by chance that making a hidden window visible with a new/another size, followed by hiding the previous window, also doesn't show jitter. This procedure is much more efficient than a create/destroy sequence. So at the start of my program I just created two windows, the first one hidden and the second one visible. The code snippet below should explain the procedure for jitterless resizing in more detail:
........
i = prm->hpi; // get current index
h1 = prm->parent[i]; // get current handle
flags = SWP_NOCOPYBITS;
flags |= SWP_NOSENDCHANGING;
// if DWM tries to make a mess of it:
// DWM enabled top border right border
if( prm->parent[1] && ( rgn == TBE || rgn == LBE ) )
{
i = i + 1 & 1; // get new index
prm->hpi = i; // save new index
h2 = prm->parent[i]; // get new handle
prm->hParent = h2; // set as current one
flags |= SWP_NOREDRAW; // bypass message pump
flags |= SWP_SHOWWINDOW; // make h2 visible
SetWindowPos( h2, HWND_TOP, px, py, cx, cy, flags );
PaintParent( h2 ); // paint it now
DwmFlush(); // wait till finished
ShowWindow( h1, SW_HIDE ); // make h1 invisible
}
// DWM disabled or dragging the right or bottom border:
else SetWindowPos( h1, HWND_TOP, px, py, cx, cy, flags );
One more thing: use DwmFlush()
to ensure all painting of the new window is finished and then hide the other window, otherwise some flicker will be visible. Of course above procedure is a little slower than a regular one. On my system (with a i5-3570K processor) 3..26ms, depending on the size of the window and its content. But at least that horrible jitter has gone.
I do realize that it's a pretty dirty trick, so if someone knows a neater solution, please, let us know.
Upvotes: 2
Views: 1938
Reputation: 3843
That two-window solution is very creative! I don't think I can apply that solution because my window is an OpenGL window with heavy state that would have to be maintained/replicated across window instances.
I think I can provide some more insight about why you kept seeing that jitter despite messing with all the usual suspects like SWP_NOREDRAW
and SWP_NOCOPYBITS
.
I ran into the same jitter problem and discovered that since apps under Windows 8/10 Aero don't draw directly to the screen, but rather draw to offscreen buffers that are then composited by the evil DWM.exe window manager, it turns out that DWM actually adds another layer of BitBlt
-type behavior on top of the existing legacy XP/Vista/7 BitBlt
behavior.
And the DWM blit behavior is even more crazy because they don't just copy the client area, but they actually replicate pixels at the edges of your old client area to make the new one. Unfortunately, making DWM not do its blit is much harder than just passing some extra flags.
It seems like your two-window trick fools DWM into not doing the extra blit, but I am looking for a way to accomplish that with one window.
I don't have a 100% solution but I hope the above info will help, and I do have code for an implementation of Ben's cool idea to time drawing to minimize the chances of DWM doing its blit:
Enjoy!
Upvotes: 0
Reputation: 31
I found a solution for the problem. Please, see the latest update of the original message.
Upvotes: 0
Reputation: 35673
It looks like under Windows 8.1 and above, you must cooperate with DWM rather than going around it.
This means that you have to find out the schedule of when composition takes place via DwmGetCompositionTimingInfo
, and ensure that you slot your rendering events into the queue at appropriate moments. You may also find you need to re-invalidate and re-paint the window just after the WM_SIZING event, or even use your own timer to paint more often than the WM_SIZING events are sent. E.g. if DWM is compositing at 50 fps, but you are only getting then WM_Sizing events per second, then if you use your own timer with GetWindowPos
you may be able to paint more often than if you rely on WM_SIZING.
You may find that judicious use of DwmFlush
just after painting may also help reduce this jitter.
Upvotes: 1