Reputation: 21
I'm writing a program which needs a DPI aware, borderless fullscreen top-level OpenGL window. The program has only this main window for 99% of the time.
The problem I'm having is the client area of the window is erased by windows when the window becomes inactive. This only occurs when DPI aware, fullscreen and borderless(i.e. zero non-client area).
I have found a workaround to this, by catching WM_NCACTIVATE and returning 0 which prevents windows from processing the NC redraw. It seems that the windows non-client redraw procedure erases the client area if the non-client area is zero.
But, when I create a DialogBox (child of main hWnd), it causes the main window to become inactive (obviously).
If I return 0 from WM_NCACTIVATE, mouse and keyboard events do not get passed to the dialog box proc so the program becomes locked.
Using a global flag I can deactivate the workaround before creating the dialog, then redraw my main GL screen on WM_INITDIALOG but this causes a rather ugly screen flash that I'm trying to prevent.
So my question is: How do I prevent windows from erasing my client are of main wnd, without suppressing WM_NCACTIVATE?
Alternately: How to avoid the window erase, delay, then redraw flash that occurs when creating the dialog?
FYI, The code I'm using to create the main window, run the message loop and draw a GL scene is essentially pinched from the HeNe examples. I know these are very dated, but I find them easy to build from.
I've changed the HeNe code to WinMain() and perform my OpenGL drawing only as the program requires (outside of the main loop and outside of WM_PAINT). Redrawing the scene and SwapBuffers() inside of WM_PAINT and WM_NCPAINT does not fix the problem.
To make the window fullscreen, I use Raymond Chen's code:
https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
I have also tried c-smile's code to make fullscreen, which behaves identically to Raymond Chen's:
Windows 10, DPI scaling and fullscreen
For the record, I'm using PerMonitor V2 but it dosent seem to matter which mode I use. Ive tried setting using both API and manifest file.
VS2019 v142; SDK 10.0.18362.0
Upvotes: 2
Views: 738
Reputation: 11
I resolved this for a Qt application on Win10. My program is DPI aware and borderless, but is not fullscreen. Nevertheless, I had the same issue where:
To resolve this, I had to change how I remove the non-client area. Previously I was using a Qt-specific function on window creation like so:
setWindowFlag(Qt::FramelessWindowHint);
I removed that and added a handler for WM_NCCALCSIZE calls which unconditionally returns 0. That removed the non-client area and, for whatever reason, doesn't cause the redraw on activation despite not having a handler for WM_NCACTIVATE.
In short, the only thing I do to remove the non-client rect is handle WM_NCCALCSIZE. I don't call into any WINAPI functions. I don't override WM_NCACTIVATE because doing so prevents dialogs from working correctly.
Here's my WndProc in full. This is for a Qt application, but nativeEvent
is just a thin wrapper around the native WndProc.
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* msg = static_cast<MSG*>(message);
LRESULT hitTestResult = 0;
auto handled = DwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, result);
if (handled)
return true;
static bool resizing = false;
switch (msg->message)
{
case WM_NCHITTEST:
*result = HitTestNCA(msg->hwnd, msg->wParam, msg->lParam, this);
if (*result != HTNOWHERE)
return true;
return false;
case WM_NCCALCSIZE:
// Setting the result to zero removes the non-client rect. This is
// a hardcoded Microsoft thing.
*result = 0;
return true;
default:
return false;
}
// Unreachable
}
Upvotes: 1