Window regions, moving children, DWM, and the white blocky mess it can create - c++

The setup: I have a top-level window with a region defined (created with SetWindowRgn()), and I have a child element that is moved (with SetWindowPos()) such that some of its pixels then overlap the clipped portion of the parent's window region.
The result: Those pixels become filled with fully opaque, fully white pixels, instead of remaining fully transparent (since it's outside its parent's region). It isn't that the child window is being drawn when it shouldn't, as the offending pixels are white regardless of what the child window looks like.
Below, the small orange child window has been moved around a bit along the edge of the parent. This only happens along the edges that have a transparent window region (so the white pixels are always constrained within the maximum rectangle of the parent window).
Things correct themselves if the parent window is hidden and then shown (just invalidating and forcing a redraw does not clear the white pixels).
This has been observed on both Vista and 7. This behavior goes away if I disable the Desktop Window Manager (DWM). In one case, it also went away after updating graphics drivers. Perhaps it's related to this issue?: Vista live thumbnail issue with SetWindowRgn. I was originally going to just file this away as a rare bug, but it's cropped up enough to warrant a lot more scrutiny.
Has anyone else run up against this before? Any insights into how DWM and window regions interact?
Also, I'm aware I can disable DWM per-application, but that disables it for everything while the app is running, in addition to causing the screen to blip on startup and shutdown, and that's really not a much better problem.

I hate to answer my own question again, but I've found a work-around. I found that setting the window's region again clears any of the stray white pixels without causing any ugly redrawing or flashing anywhere else. This works even if the region I am setting is the same as the existing region, so something as simple as this works:
HRGN hRgn = CreateRectRgn(0,0,0,0);
GetWindowRgn( hWnd, hRgn );
SetWindowRgn( hWnd, hRgn, true );
DeleteObject( hRgn );
As an added bonus (or rather as another bizarre aspect of this problem), if I call this shortly before moving the window, then none of the white pixels show up, but to just cover my bases I have it perform this step both before and after animating the translation of any windows.
It may be possible that the issue then lies with some state I'm putting the window into after its creation, which gets cleared by re-setting the region. It'd be nice to know the root cause, but as this feels like I'm working around a driver bug, perhaps I'll just never know what's the root cause.

Related

OpenGL flickering/damaged with window resize and DWM active

I have a wxWidgets application that has a number of child opengl windows. I'm using my own GL canvas class, not the wx one. The windows share their OpenGL context.
I don't think the fact it is wxwidgets is really relevant here.
The opengl windows are children of a windows that are siblings of one another, contained within a tab control. Kind of an MDI style interface, but it is not an MDI window.. Each one can be individually resized. All works lovely unless Aero is enabled and the DWM is active.
Resizing any window (not even the opengl ones) causes all of the opengl windows to flicker occasionally with a stale backing-store view that contains whatever rubbish has been on the screen at that point that is not opengl. This ONLY happens with Aero enabled.
I'm pretty certain that this is the DWM not actually having the opengl contents on its drawing surface backing store and the window not being repainted at the right moment.
I've tried so many things to get round this, I do have a solution but it is not very nice and involves reading the framebuffer with glReadPixels into a DIB and then blitting it to the paint DC in my onPaint routine. This workaround is only enabled if DWM is active but I'd rather not have to do this at all as it hurts performance slightly (but not too bad on a capable system - the scenes are relatively simple 3d graphs). Also mixing GDI and opengl is not recommended but this approach works, surprisingly. I can live with it for now but I'd rather not have to. I still have to do this in WM_PRINT if I want to take a screenshot of the child window anyway, I don't see a way around that.
Does anyone know of a better solution to this?
Before anyone asks I definitely do the following:
Window class has CS_OWNDC
WM_ERASEBACKGROUND does nothing and returns TRUE.
Double Buffering is enabled.
Windows have the WS_CLIPSIBLINGS and WS_CLIPCHILDREN window styles.
In my resize event handler I immediately repaint the window.
I've tried:
Setting PFD_SUPPORT_COMPOSITION in the pixel format descriptor.
Not using a wxPaintDC in the paint handler and calling
::ValidateRect(hwnd, NULL) instead.
Handling WM_NCPAINT and excluding the client area
Disabling NC paint via the DWM API
Excluding the client area in the paint event
Calling glFlush and/or glFinish before and after the buffer swap.
Invalidating the window at every paint event (as a test!) - still
flickers!
Not using a shared GL context.
Disabling double buffering.
Writing to GL_FRONT_AND_BACK
Disabling DWM is not an option.
And as far as I am aware this is even a problem if you are using Direct3D instead on OpenGL, though I have not tested this as it represents a lot of work.
This is a longshot, but I just solved exactly this same problem myself.
The longshot part comes in because we're doing owner draw of the outline of a captionless group box that surrounds our OpenGL window (i.e., to make a nice little border), and that may not describe your case.
What we found caused the problem was this:
We had been using a RoundRect() call (with a HOLLOW_BRUSH) to draw the outline of the group box. Changing it to a MoveToEx() and LineTo() calls to ensure JUST the lines are drawn and nothing gets done inside the group box kept the GDI from trying to unexpectedly repaint the whole content of the control. It's possible there's a difference in invalidation logic (or we had a bug somehow in loading the intended hollow brush). We're still investigating.
-Noel
My app has only a single OpenGL window (the main window) but I ran into some nasty DWM tearing issues on window resize and I wonder if one of the solutions may work for you.
First of all, I found that during window resize there are at least two different bad guys who want to "help" you by modifying your client area before you have a chance to update the window yourself, creating flicker.
The first bad guy dates back to a XP/Vista/7 BitBlt inside the SetWindowPos() that Windows does internally during window resize, and can be eliminated with a trick involving intercepting WM_NCCALCSIZE or another trick involving intercepting WM_WINDOWPOSCHANGING.
In Windows 8/10 we still have that problem but we have a new bad guy, the Aero DWM.exe window manager, who will do his own different kind of BitBlt when he thinks you are "behind" updating the screen.
I suspect that the rubbish pixels you are seeing might actually be an intentional and very very poor attempt by DWM to fill in something "acceptable" while it waits for you to draw. I discovered that DWM extends the edge pixels of old client area data when it blits the new client area, which is insane.
Unfortunately, I don't know of any 100% solution to prevent DWM from doing this, but I do have a timing hack that greatly reduces the frequency of it.
For source code to the WM_NCCALCSIZE/WM_WINDOWPOSCHANGING hack as well as the DWM timing hack, please see:
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
Hmm, maybe you have ran into the same issue: if you are using "new" MFC
it will create and application with Tabs and Window Spliter.
The splitter has some logic (I am guessing somewhere around transparent window and drawing XOR
lines for the split) that causes this behavior. Remove the splitter to confirm it resolve
your issue. If you need split functionality -- put in a different splitter.
Also Tabs allow docking and again splitting the windows that has the same issue -- remove/replace.
Good luck,
Igor

Draw on screen with GDI+ (or GDI) similar to Inspect

I'm trying to draw on the screen (the whole screen, on top of every other window) using GDI+.
I've passed NULL to GetDC to get a HDC to the screen, and then used that to create a Graphics object, and used DrawRectangle to draw rectangles on the screen.
Everything works..except...the inside of the rectangle won't update.
Like if I draw it over a command prompt, and move the command prompt, the inside of the rectangle remains black.
I expect to see whats under the rectangle.
Here's the code that's doing the drawing..
Pen BluePen(Color(255, 0, 255, 0), 2);
Graphics graphics(screenDC);
graphics.DrawRectangle(&BluePen, myRect);
Pretty simple, so is there something I have to do to get the inside of the rectangle to update when the screen does? Or to get it truely transparent.
================= EDIT =================
Well I had given up on this, and assumed it wasn't possible, until...I realized the Inspect tool that comes with the Windows SDK does this perfectly.
I would like to recreate something similar to the highlight rectangle, and if I select a window (such as Firefox) and then bring Inspect into focus I can move it around freely with everything being updated perfectly.
There's not even any flickering.
So...does anyone know how Inspect manages to do this?
Also answers in GDI instead of GDI+ are fine...
In windows the screen (and the windows ...) surface(s) are ... volatile, like sandboxes. The "overlapping" of windows and the re-painting of uncovered surfaces is an illusion made by proper event management.
Everything is drawn remain there until something else is drawn over it.
"Uncovering" a surface makes the window representing that surface to receive a WM_PAINT message. It's up to that window procedure to react to that message by re-painting everything is supposed to be under it.
Now, unless you intercept somehow the WM_PAINT message that is sent to the desktop window, you have mostly no chance to know the desktop needs a repaint and hence your paint code will not be called and no repaint will happen. Or better it happens following just the desktop window updating code, that's not aware of your paint.

Strange winAPI behaviour

I have sub classed a tab control to give it a background. I have used the clipping functions to clip the drawing area to the update region. This works, except for when I move the window of the screen and back again.
When it does this, it occasionally sets the clipping region to the whole screen. This is fine except that none of the controls redraw and end up hidden behind the background. How do I know whether or not to redraw the background when I get this update region. It would be 100x easier to develop this if I saw the source code for the tab control, but that isn't going to happen.
All help or suggestions welcome, but I really do need a straight-forward answer.
By "clipping region" I assume you mean the area that has to be redrawn that windows passes to you.
Try this: The paint message handler should bitblit the area of the background image that corresponds to the part of the window that needs to be refreshed (so you don't draw over things that don't need updating). Then let the base class handle the rest.
If it's setting the repaint region to the entire window the tab control code should redraw everything after you've painted the background.
Having code to look at would help

Black flicker while resizing translucent Qt widget (only when Aero is enabled)?

I have a top-level Qt widget with the FramelessWindowHint flag and the WA_TranslucentBackground attribute set. It has several children, each of which draws an image on it. They are not in a layout. Instead, I simply move them around when something changes (it is not user-resizable).
There are two states to the window - a big state and a small state. When I switch between them, I resize the window and reposition the children. The problem is that as the window resizes, a black box is briefly flashed on the top-level window before the images are painted over it.
The problem goes away if I disable Aero. I found brief mention of this problem being fixed in an article describing a new release of Qt (this release is long past), but it still doesn't work.
Any ideas why?
Thanks!
I don't have experience with Qt specifically, but I have worked with other windowing toolkits. Typically you see this kind of flashing when you are drawing updates directly to the screen. The fix is to instead use Double buffering, which basically means that you render your updates into an offscreen buffer (a bitmap of some sort, in the purest sense of the word), and then copy the entire updated image to screen in a single, fast operation.
The reason you only see the flickering sometimes is simply an artifact of how quickly your screen refreshes versus how quickly the updates are drawn. If you get "lucky" then all the updates occur between screen refreshes and you may not see any flicker.

Flickering child windows with alpha channels

When drawing child controls containing bitmaps with per-pixel alpha channels, we are getting quite a lot of flickering whenever they need to be redrawn. The actual blending is working correctly. I've found a lot of info about reducing flicker (such as this question or this site), but I can't seem to find anything that applies specifically to this situation.
For example, I've got a button with a few different bitmaps that are alpha blended and blitted to the window, depending on the state of the button. When their state changes and I need to draw a different bitmap, I need to redraw the background first, or else it blends with pixels left over from the previous state's bitmap. This is where I am getting some flickering, where I get a bit of the background tearing in occasionally.
The problem is made more complicated by having the top-level parent windows drawing a bitmap background, rather than a solid color, along with the possibility of having child controls overlapping; just multiplying the underlying color into the child's bitmap is out of the question, as is using WS_CLIPCHILDREN.
Since the windows have a bitmap background, I'm returning true on WM_ERASEBKGND, to avoid drawing a color that will just be overwritten.
Of course, double buffering would seem to solve all of this, but I have not been able to get it to work right. I've set WS_COMPOSITED for top-level windows, and WS_TRANSPARENT for child windows. When it comes time to redraw a child window with a new bitmap, I am having a few issues (most likely from me not understanding how the draw order is working in this situation):
If I call InvalidateRect() and pass the child handle, the child window is indeed redrawn, but the background is not redrawn, and so the pixels accumulate on top of each other, blending together.
If I call InvalidateRect() and pass in the parent handle, with a rectangle consisting of the child window's dimensions, the background is redrawn, but the child window is not.
If I do both of the above, then the background is redrawn as well as the child window, and it looks exactly as I'd want -- except that by doing so, I've managed to make it flicker again (which isn't really surprising, since it seems terribly hackish to call InvalidateRect() twice like that, as I'd guess that each call is probably causing the buffers to flip, which defeats the purpose).
What I've come to conclude is that I don't really understand how I need to modify my program to handle double buffering, or if double buffering will even help with this situation. I feel like it definitely would, but I don't quite understand how I need to modify things to get everything to play nicely again.
Are you using layered windows? If not maybe try it out.
Also for double buffering consider this technique.
This could be completely off base - my gui days were a long long time ago...
But couldn't you just precompute the blends for your different states? I assume your button can be enabled/disable and up/down, so that's only 4 combinations. Why not precompute the combined bitmaps?
Or is the problem the interaction of already combined bitmaps with the existing state?