Borderless Window Using Areo Snap, Shadow, Minimize Animation, and Shake

Borderless Window Using Areo Snap, Shadow, Minimize Animation, and Shake

After using Spy++ to inspect Steam's window (its window styles, how it replies to window messages) and trying to match everything it does, combined with the DWMAPI calls from this C# borderless window behavior, I believe I figured it out.

To hide the window's border, handle the WM_NCCALCSIZE message in your WindowProc:

case WM_NCCALCSIZE: {
if (window->is_borderless) {
return 0;
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}

To enable the shadow, all you need to do is:

MARGINS borderless = {1,1,1,1};
DwmExtendFrameIntoClientArea(hwnd, &borderless);

To turn it back off, restore the default margins MARGINS windowed = {0,0,0,0};.
Perhaps throw in a SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS | SWP_NOSIZE | SWP_NOMOVE ); also, to make sure the frame gets redrawn.

However, this does not seem to work with all window styles, apparently your window style must not contain a titlebar. Title bars work fine, and adding one seems to enable the minimize animation.

The simplest window style I got the shadow to work with was WS_POPUP | WS_THICKFRAME, to also get aero snap, maximizing, minimizing, and the smooth minimize animation I used WS_POPUP | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION.

Changing DWMWA_NCRENDERING_POLICY or DWMWA_ALLOW_NCPAINT via DwmSetWindowAttribute does not appear to be required, the default settings seem to work.

One word of caution: DwmExtendFrameIntoClientArea does exactly what the name suggests, so if you are drawing an image with an alpha channel directly into your client area (say with opengl, direct3d/2d), a small frame will be visible through it:

borderless window with shadow and frame showing in client area

So you might have to put a non transparent widget, brush or something behind the transparent element.

If all goes well, it should then look like this:

Sample Image

Here is a small example project, F11 toggles borderless/windowed mode, F12 toggles the borderless shadow on and off.

Aero Snap with Borderless Window in Qt

I was looking for this kind of Qt window and I have finally found a solution.

This GitHub example does the job like a charm (thanks to deimos1877)!
https://github.com/deimos1877/BorderlessWindow

Be sure to use visual studio compiler to get the needed DLL and it should work.
This example include aerosnap support, borderless window, minimize effect, aero shadows.

Borderless window in Qt on Windows which supports native features: aero snap, DWM resize and minimization

I've found a workaround for this problem.

Instead of using Qt main window, i've created a simple WinAPI borderless window, like in this SO discussion. Then i added QWinWidget from QtWinMigrate project, and filled window with it.

As result, main window and resizable edges are handled by WinAPI, and everything inside main window is handled by QWinWidget. And with QWinWidget you can create Qt gui like in any other Qt app.

Sample Image

Here is a small example project on GitHub.

Borderless window with Aero Snap too large in maximized state

My first try, was setting the window geometry to the available geometry:

QRect rect = QApplication::desktop()->availableGeometry();
setGeometry(rect.left() , rect.top(), rect.right(), rect.bottom());

The only Problem is that the window is a pixel too small on the right and bottom side and

setGeometry(rect.left() , rect.top(), rect.right() + 1, rect.bottom() + 1);

gives me an error:

QWindowsWindow::setGeometry: Unable to set geometry 2560x1400+0+0 on QWidgetWindow/'MainWindowWindow'. Resulting geometry:  2576x1416+-8+-8 (frame: 0, 0, 0, 0, custom margin: 0, 0, 0, 0, minimum size: 45x13, maximum size: 16777215x16777215)

Then I looked at the rectangle coordinates of Visual Studio 2015 and they are the same size as my implementation of a borderless window, 8 pixels larger in every direction.

I can give the contents of my window a margin of 8 so it doesn't clip out of the screen if the window is maximized and set the window region:

setContentsMargins({ 8, 8, 8, 8 });

HRGN WinRgn;
RECT winrect;
GetClientRect(hwnd, &winrect);
WinRgn = CreateRectRgn(8, 8, winrect.right - 8, winrect.bottom - 8);
SetWindowRgn(hwnd, WinRgn, true);

When the window gets restored, we need to reset the previous changes.
The result is:

case WM_SIZE:
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hwnd, &wp);
if (wp.showCmd == SW_MAXIMIZE) {
setContentsMargins({ 8, 8, 8, 8 });

HRGN WinRgn;
RECT winrect;
GetClientRect(hwnd, &winrect);
WinRgn = CreateRectRgn(8, 8, winrect.right - 8, winrect.bottom - 8);
SetWindowRgn(hwnd, WinRgn, true);
UpdateWindow(hwnd);

is_fullscreen = true;

} else {
if (is_fullscreen) {
setContentsMargins({ 0, 0, 0, 0 });
SetWindowRgn(hwnd, NULL, true);

is_fullscreen = false;
}
}
break;


Related Topics



Leave a reply



Submit