melak47 / BorderlessWindow

basic win32 example of a borderless window (with aero shadows)
Creative Commons Zero v1.0 Universal
480 stars 76 forks source link

Win10: Resize outside of window frame #11

Closed mrgreywater closed 7 years ago

mrgreywater commented 8 years ago

I was wondering if there was any way to recreate the windows 10 behaviour that allows resizing on a transparent border around the (now frameless) window. Visual Studio 2015 seems to be the only other application that seems to have recreated a similar behaviour, even if slightly differently (It allows resizing above the caption aswell, which is not possible for default windows).

I imagine one way to do it would be enabling WS_CAPTION | WS_POPUP | WS_THICKFRAME, removing the WS_CAPTION size from the top of the window in WM_NCCALCSIZE (without returning 0) and then drawing a transparent color in WM_NCPAINT, even though I'm not convinced it would work, and wonder if there may be an easier way to achieve the same effect.

See comment: https://github.com/melak47/BorderlessWindow/blob/master/BorderlessWindow/src/Window.cpp#L103#L105

melak47 commented 8 years ago

First some observations:

So it looks to me like 7 out of 8 pixels of the window frame are simply transparent, but still part of the window. In theory, if we carefully construct the client rectangle in WM_NCCALCSIZE like you mentioned, so that it does not simply expand to the entire window, we should achieve the desired effect.

A quick test shows that this almost works: test

The transparent resizable border is still present and functional, unfortunately so is the 1 pixel border, and adjusting the client rect further out just pushes that border further out. I was also unable to draw over this, since it's not part of the client area. Maybe it's possible to do something in WM_NCPAINT to get rid of it, but I don't really know GDI. Anything I tried to draw there seemed to wreck the entire non client area permanently, even after switching back to bordered mode.

melak47 commented 8 years ago

Hm, it seems possible to invoke DefWindowProc in WM_NCPAINT to get the transparent border, then paint over the non-transparent part... ...but even if I was doing it correctly, this doesn't seem like a good solution if your window content doesn't have a flat backgroud color. You'd probably need to copy into a bitmap and draw the one pixel border using that to get a seamless look - for e.g. a video player or a game this seems like a bad idea.

mrgreywater commented 8 years ago

Nice investigation! If that doesn't work, maybe we could increase DwmExtendFrameIntoClientArea on the bottom, right and left side by 8 pixels on Windows10 and draw a transparent color over the custom DWM border. Even though this would mean you need to manually modify the client rect when using GetClientRect for drawing the actual window contents, since the transparent border should not be part of the actual client area. And I don't know if the DWM shadow would work correctly.

melak47 commented 8 years ago

Additionally, I think you would also have to handle all the special cases like maximizing and snapping to a screen quadrant/half manually, which is something I'd want to avoid...

IMAN4K commented 8 years ago

Hi melak47 Thanks for sharing this window snippets. Here is a small window example based on your one https://github.com/IMAN4K/QtPro/blob/master/Ui/Qt5.5.1/_Other/window_frameless.cpp

It's borderless, has Drop Shadow, has snap feature and also can be resize from outside of it's frame enter image description here These lines remove the caption And these lines remove the colored frame

But there is an issue and my window doesn't have animation on minimize,maximize and close like a native window! I will appreciate it if you take a look and help me on this i don't have strong knowledge in win32API

mrgreywater commented 8 years ago

@IMAN4K WS_CAPTION is required for the minimize and maximize animation. If you remove it, it will also disable those animations. To my knowledge there is no way to enable the animations whilst not specifying WS_CAPTION.

IMAN4K commented 8 years ago

@mrgreywater WM_NCCALCSIZE also removes the caption right ? but still animation are there

melak47 commented 8 years ago

@IMAN4K Unfortunately, your sample only appears to work because the border and contents of the window are now white. If you try to fill the client area with another color, you will see that the border is not gone:

default

You are right, we can remove the titlebar by adjusting the client rect in WM_NCCALCSIZE as I tried above, however I still can't seem to get rid of the other borders that way:

2

IMAN4K commented 8 years ago

@melak47 What about InflateRect ? could it be helpful(at least for default color)?

case WM_NCCALCSIZE: {
        const int cxBorder = -BORDER_WIDTH;
        const int cyBorder = -BORDER_WIDTH;
        InflateRect((LPRECT)lParam, cxBorder, cyBorder);
        return 0;
    } break;

It seem's work except the top! Do you have any idea on this ?

OR process WM_SIZING and use AdjustWindowRect ?

melak47 commented 8 years ago

I was doing it manually as you can see here: https://github.com/melak47/BorderlessWindow/blob/Win10/BorderlessWindow/src/Window.cpp#L83-L96

I just noticed though that I'm not handling wParam == FALSE in which case I'm possibly reading bogus memory.

melak47 commented 7 years ago

While it is possible to paint over the title bar using DwmExtendFrameIntoClientArea as demonstrated here: https://github.com/oberth/custom-chrome, in Windows 10 it's no longer possible to also have the left, right and bottom sides of the frame inside the client area as described in this msdn article.

Because of that, it is impossible to draw over the visible part of the frame without also destroying the transparent effect - at least using a single window.

Visual Studio 2012+ and Office 2013+ for example sidestep this by having multiple windows, a transparent window to which the shadow (or glow) is rendered (which also serves to capture the mouse and enable resizing outside the frame), and one or more "main" windows, with completely custom drawn title bars and window frames.

That's a lot of effort for a very small feature which I feel is beyond the scope of this little sample app, so I'm closing this issue.