Redrawing of Win32 OpenGL context can't keep up with window resizing - c++

I've been working on an OpenGL-based application that runs directly on Win32. I've noticed an issue where when I resize the window, the drawing can't keep up around the edges. Here's a video of the issue in action. (Note the bottom-right and top-right corners of the window)
I am running the redraw function inside of my WM_SIZE event, but it still has a slight delay.
If there is a way to make it not have this visual artifacting - great! If not, how can I keep the window from updating its size until the controls have been drawn?

Related

Updating hidden window using winapi

I am creating a simple clock application. Whenever I make it disappear and restore it after a while I get an uncomfortable lag effect when my window is redrawing itself after some short period of time. I want to see changes immediately. It seems that window is not getting WM_PAINT messages while being not present on the screen (and this is actually the place I draw stuff). How to force Windows to redraw window just before showing up on the screen rather than afterwards?

Flickering on window when resizing from left side

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.
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.
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)?

Draw moving icon that is top most all the time like mouse cursor and work for full screen apps

I need to draw an icon that moves approximately in sync with mouse cursor and is always on top of all windows.
OS: Windows 7
I have a solutions that work to some extend by drawing my icon in a top most transparent window. There are some major drawbacks in this solution since that top most window interferes with other top most windows and some full screen apps do not work correctly. Examples are start menu and task bar that will overlay my window if I do not regulary set it to be top most. For some full screen applications performance of updating position of window with icon hugely drops and it does not follow mouse smoothly.
There is another method that I came across where an icon is drawn directly to the device context of desktop Draw mouse pointer icon?. This solution has a drawback that there seems to be no good way of how to remove "trail", especially if desktop content changes quickly.
So my question: is there an ultimate solution that does not have the above mentioned problems?
Is it possible to draw above all windows in the "layer" of mouse cursor? Or make a second mouse cursor with my custom icon that I will control (I know that widows can display two independently controlled mouse cursors like CPNMouse)?
Can someone point me to the right direction?
Thanks!
Use a top-most window with transparency set via WS_EX_LAYERED / UpdateLayeredWindow.
If you set the WS_EX_TRANSPARENT style as well then the window won't intercept mouse input.

How to intercept mouse events of a transparent window?

I have a transparent window (created with WS_EX_LAYERED) and I'd like to receive mouse events of the zero-alpha regions.
As far as I know, I could:
1) Use mouse hook
2) Paint the background with almost completely transparent color (that has an opacity of 1)
However, the first solution is time consuming and the 2nd one will slow my rendering time as my window is stretched almost all over the desktop and most of the pixels are completely transparent at the moment.
Is there another way receiving those mouse events?
According to MSDN:
Hit testing of a layered window is
based on the shape and transparency of
the window. This means that the areas
of the window that are color-keyed or
whose alpha value is zero will let the
mouse messages through. However, if
the layered window has the
WS_EX_TRANSPARENT extended window
style, the shape of the layered window
will be ignored and the mouse events
will be passed to other windows
underneath the layered window.
However, in a new thread you could get continuously the coordinates of the mouse with GetCursorPos and if the position is inside one of your icons (regardless, that it's over a zero alpha pixel inside the icon) you handle it. Not too much better than the hook

OpenGL window cleared with no WM_PAINT message

I have an application with three MDI windows, all of them showing OpenGL content. On XP, everything works fine. But on Vista/Win7 the mdi child windows don't refresh properly.
After startup, all windows show their content properly. But when I change the focus from one mdi window to the next, those two windows are cleared (i.e., they only show white, no content). I have no idea why the windows get cleared, they don't receive any WM_* message when that happens, and of course don't receive a WM_PAINT message either.
When resizing those windows, I correctly get the WM_PAINT message (after WM_SIZE) and redraw the content, but then the window gets cleared too, which results in a strange flicker while resizing. After resizing stopped, the window stays cleared (white) until I manually force a refresh.
This happens independently of Aero enabled or disabled.
Any idea why this happens?
I'm surprised it works on XP. In my (limited) experience dabbling with OpenGL, WM_PAINT is not always the best place to redraw OpenGL scenes. Most likely the content is getting wiped out at the driver level. You can check for this by seeing what happens when one of your MDI windows happens to span two monitors connected to two different video cards.
Try the following:
Reinitialize your OpenGL contexts after WM_SIZE occurs.
Draw on-demand instead of in WM_PAINT. In your handler for WM_PAINT, do nothing. Use a timer or some other mechanism to periodically trigger updates of your displays.
Flicker is usually caused by interference via WM_ERASEBKGND. If you haven't already, intercept WM_ERASEBKGND and do nothing in the regions where you are displaying OpenGL content.
Use the CS_OWNDC window style on any windows hosting OpenGL content so that the HDC doesn't change per-message/per-call during the lifetimes of your MDI windows.
Other rarer causes of interference that might apply (since you are using MDI windows)
WM_NCPAINT and other related Non-Client drawing messages- you can workaround these by moving your OpenGL content to a child window with no border, inside the MDI windows.
Incorrect/Incompatible default features for OpenGL on your video card that explicitly require overlays or implicitly use them (frequent cause of issues in overlapping contexts). Unfortunately, diagnosing this out of my realm of knowledge, but some testing may shed some additional light here.