Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Windows 11 "Snap Layout" to the custom title bar (WindowChrome) #4825

Open
d2phap opened this issue Jul 9, 2021 · 61 comments

Comments

@d2phap
Copy link

d2phap commented Jul 9, 2021

As Windows 11 introduce Snap Layout when we hover on Restore/Maximize caption button, I want to have this feature on my custom title bar using WindowChrome.

The current SystemCommands class does not have it:

public static class SystemCommands
{
  public static void CloseWindow(Window window);
  public static void MaximizeWindow(Window window);
  public static void MinimizeWindow(Window window);
  public static void RestoreWindow(Window window);
  public static void ShowSystemMenu(Window window, Point screenLocation);
}

Custom Title bar

image

Default Title bar

image

@lindexi
Copy link
Member

lindexi commented Jul 9, 2021

Ref #4749

@batzen
Copy link
Contributor

batzen commented Jul 10, 2021

Does anyone know if there is an API to trigger the new snap layout "menu"?

@miloush
Copy link
Contributor

miloush commented Jul 11, 2021

It is not a system command.

If you have a custom maximize button, it is your job to tell that to the OS by responding HTMAXBUTTON to WM_NCIHITTEST. That will give you the snap options on hover.

I think there is an opportunity for API improvement to simplify this task through an attached WindowChrome property

@mdtauk
Copy link

mdtauk commented Jul 11, 2021

It is not a system command.

If you have a custom maximize button, it is your job to tell that to the OS by responding HTMAXBUTTON to WM_NCIHITTEST. That will give you the snap options on hover.

I think there is an opportunity for API improvement to simplify this task through an attached WindowChrome property

This would be helpful for Windows Terminal, as well as other WinUI 3 apps.

@batzen
Copy link
Contributor

batzen commented Jul 11, 2021

@miloush While returning HT.MAXBUTTON works and shows the menu it causes various unwanted side effects.

  • MouseOver does not work anymore (highlight)
  • Clicking a button which returned some window button HT causes the system button to be rendered for a short time

WPF_HT_Button

@miloush
Copy link
Contributor

miloush commented Jul 11, 2021

@batzen I guess you can still handle the mouse over, however yeah I will give you that the system-rendered button on click is sad; feels like a bug in the shell.

@Splitwirez
Copy link

@miloush The events aren't even raised when the caption button HT values are returned. The WPF stuff just acts like the cursor isn't even over the window.

@ryalanms ryalanms added this to the Future milestone Aug 27, 2021
@billhenn
Copy link

billhenn commented Sep 21, 2021

We also have been digging into this issue of trying to show the Snap Layout Menu in a WPF app that uses our custom WindowChrome, where we render all custom title bar buttons. We've run into the same issues when returning HTMAXBUTTON from WM_NCHITTEST as described above, where WPF no longer receives any pointer input (due to HTCLIENT not being returned), and clicking our custom button renders a classic Win32 maximize button.

We really need some other API than responding to WM_NCHITTEST to get this working for those of us who have powerful custom window chromes and need the WPF elements in those chromes to remain responsive.

@batzen
Copy link
Contributor

batzen commented Sep 22, 2021

FYI: The WindowChromeBehavior from ControlzEx will provide a solution for this problem during Hacktoberfest.

@mevey
Copy link

mevey commented Sep 23, 2021

@batzen Are you able to share with us a copy of the test app so we can get to the bottom of this?

@batzen
Copy link
Contributor

batzen commented Sep 25, 2021

I can share a link to the branch in ControlzEx as soon as i pushed the changes.
Feel free to ping me if i didn't do so till monday.

@batzen
Copy link
Contributor

batzen commented Sep 26, 2021

@mevey You can grab the code from https://github.com/ControlzEx/ControlzEx/tree/features/Win11Support Please note that it's still a WIP and i haven't yet implemented support for rounded corners, but the snap menu on the maximize button works without all the negative side effects everyone observed.

@mevey
Copy link

mevey commented Sep 29, 2021

Thank you @batzen, this is extremely helpful as we try to understand root cause.

@billhenn
Copy link

We also have worked the past week on Windows 11 features in our own WindowChrome and have managed to get the snap layout menu showing without the two negative side effects we found in our first attempt. Our changes can be summarized as:

  1. Handle WM_NCHITTEST and return HTMAXBUTTON when over our custom WPF Button that represents the Maximize button in our window chrome's title bar. This gets the system to show the snap layout menu when the mouse is over our Maximize button.

  2. Mark the WM_NCLBUTTONDOWN message as handled when over HTMAXBUTTON per number 1 above. This prevents the classic 3D Win32 button from showing when clicking our WPF Maximize button.

  3. Handling various WM_NC* mouse messages and using SendMessage to send related messages to the Window to mimic "client area" mouse messages with translated POINT values so that WPF can receive them. This ensures the pressed state can be reflected on the button. But it doesn't help with the hover state since Win32 still thinks we are in a non-client area so WM_MOUSELEAVE gets fired by the system immediately any time we send WM_MOUSEMOVE messages ourselves, thereby making WPF's IsMouseOver fail.

While the above sounds relatively simple, it really isn't and ended up being a lot more work than we'd hoped. We've had to hack things in to handle the edge cases like proper hover state display on the button when the menu is open. It would be nice if the system could notify the window somehow when the snap layout menu was opening/closing so we could alter our hover state on our Maximize button. Right now it seems no Windows Win32 messages are sent to the window once the snap layout menu opens. It's difficult to know if the mouse then moves over that menu or not.

@batzen
Copy link
Contributor

batzen commented Sep 29, 2021

@billhenn Point 3 is the reason why I created https://github.com/ControlzEx/ControlzEx/blob/features/Win11Support/src/ControlzEx/Behaviors/WindowChrome/NonClientControlManager.cs
It's simply not possible, judging from all my experiments, to return the proper hittest result and get client area mouse messages at the same time as the area is treated as non client after the hittest result.

@billhenn
Copy link

It's simply not possible, judging from all my experiments, to return the proper hittest result and get client area mouse messages at the same time as the area is treated as non client after the hittest result.

Yes, that is the one of the most difficult things we've had to attempt to work around. It would be nice if there was a way to manually request the snap layout menu show so we could avoid the entire hacky non-client piece of things. If our WPF Button could detect a hover scenario on itself, then we could simply call some Windows API (which probably doesn't currently exist) to request the snap layout menu at a certain screen coordinate and be done with it.

@mevey
Copy link

mevey commented Oct 12, 2021

Hey folks, Just letting you know that we are still working on this issue internally and will have a response for you soon. We appreciate your patience.

@kalin-todorov
Copy link

@mevey any updates on this?

@batzen
Copy link
Contributor

batzen commented Oct 29, 2021

For anyone interested: ControlzEx/ControlzEx#151
ControlzEx has it implemented and also offers window border colors, controlling rounded borders and the custom window chrome is flicker free. If you choose to use glow windows those move/resize without any visible gap.

@ghost1372
Copy link

Hi @batzen Your example was very complex (at least for me) I used another code. I was able to show SnapLayout But I see the problems you mentioned earlier
00

You seem to have solved these problems, Can you help me solve these problems?

int x = lparam.ToInt32() & 0xffff;
int y = lparam.ToInt32() >> 16;
var rect = new Rect(_ButtonMax.PointToScreen(new Point()), new Size(_ButtonMax.Width, _ButtonMax.Height));
if (rect.Contains(new Point(x, y)))
{
    handled = true;
}
return new IntPtr(HTMAXBUTTON);

@sachinkumarrajak08
Copy link

Hi, @ghost1372 . i have checked your code in my c# wpf application ,i am getting compile time error .
can you tell me or provide any sample for how to use your code in c# wpf for button control .

@ghost1372
Copy link

ghost1372 commented Nov 2, 2021

Hi, @ghost1372 . i have checked your code in my c# wpf application ,i am getting compile time error . can you tell me or provide any sample for how to use your code in c# wpf for button control .

you should write this code in wndProc see here or here

@kalin-todorov
Copy link

Hey @gurpreet-wpf thanks for those details. However it is not clear how this should be implemented and what is the actual change? Do you have working example of Window with custom title bar supporting Snap Layout menu?

@gurpreet-wpf
Copy link
Contributor

Hi @kalin-todorov , the default implementation of this feature got fixed by Windows team. We need to work on Custom Chrome bar to have this ability.

@kalin-todorov
Copy link

Hi @gurpreet-wpf, so is there any new API that will allow us to show manually the menu?

@kalin-todorov
Copy link

Hi again @gurpreet-wpf any updates on this item?

@pchaurasia14
Copy link
Member

@kalin-todorov - Apologies for the delayed response.
Unfortunately, we don't have the snap UI support for custom titlebar, yet.

However, we're planning to incorporate this feature in upcoming releases.

@kalin-todorov
Copy link

@pchaurasia14 thanks for the reply! However, I'm more interested in the Windows API that will allow custom title bar to be implemented in a correct manner. So, is there any new Windows API that can be used to open up the snap UI manually?

@sungaila
Copy link

So, is there any new Windows API that can be used to open up the snap UI manually?

I am also interested in this Win32/WinRT API. Visual Studio is built with WPF, has custom titlebar buttons AND the Snap Layout panel is working just fine. How did they do it?

@batzen
Copy link
Contributor

batzen commented Mar 20, 2023

The requirement to get the snap menu is to return the proper hittest result when Windows asks your app.
As far as I know there is no dedicated API.

@GSonofNun
Copy link

GSonofNun commented Mar 27, 2023

I got this half working using examples people have provided. If the window is maximized, the snap layout popup appears when hovering over the "Restore" button. But if the window is not maximized, it doesn't ever show, even though I am still returning HTMAXBUTTON. Has anyone else seen this issue?

@manfromarce
Copy link

I've experimented that if you have a custom chrome but WindowStyle is not None the snap popup is only displayed if you return HTMAXBUTTON where the system button would be. That means, if the title bar buttons are smaller/larger/taller than the system ones it will only work on part of the maximize button. It works properly if WindowStyle=None, but that requires more code for fixing maximization, flicker and other stuff.

@GSonofNun
Copy link

@manfromarce you were right. Changing my WindowStyle to None made it start working when the window is not maximized. But unfortunately I don't want to use WindowStyle=None because of what you lose when you do. Hopefully this is a bug that they can fix. (@gurpreet-wpf)

@Gilfoylex
Copy link

https://github.com/Gilfoylex/WPFUiBase Here's my solution, referenced https://github.com/grassator/win32-window-custom-titlebar and https://github.com/lepoco/wpfui

@lindexi
Copy link
Member

lindexi commented Aug 29, 2023

@Gilfoylex Good, looking forward to your https://github.com/Gilfoylex/WPFUiBase

@NotYoojun
Copy link

Hi! We're developing a library that enables us to use modern styles and components in WPF applications.
It contains a whole set to modernize your application. And it's still active.
The modern window in this lib has all snap supports. See more at:

https://github.com/InkoreStudios/UI.WPF.Modern

Thanks!

@damien-c-d
Copy link

It would be nice to have this be possible. The default title bar in WPF gives off big Windows 7 vibes and seems to have been completely ignored by Microsoft.

@batzen
Copy link
Contributor

batzen commented Oct 7, 2023

@damien-c-d The default title bar in WPF is the default Windows title bar and supports snap layout. But when using a custom window chrome there is no snap layout and a plethora of other issues caused by it.
So i am not sure what you are talking about, when referring to "default title bar".
Could you clarify that?

@damien-c-d
Copy link

damien-c-d commented Oct 7, 2023

@damien-c-d The default title bar in WPF is the default Windows title bar and supports snap layout. But when using a custom window chrome there is no snap layout and a plethora of other issues caused by it.
So i am not sure what you are talking about, when referring to "default title bar".
Could you clarify that?

The default title bar is rubbish and the offers very little options in the way of customisation and theme support. That's why an overwhelming majority of UI libraries have customised the window chrome.

You're completely correct, using a custom window chrome does have those problems. Seems like a design issue to me. So really that's the only out of the box options we have in WPF. Pretty poor in my opinion.

Problem is some of the most widely used UI libraries are waiting for this to be implemented:

https://www.syncfusion.com/feedback/36976/show-snap-layout-option-while-hovering-the-maximize-button

https://feedback.telerik.com/wpf/1559117-radribbonwindow-don-t-support-window-11-snap-layout-feature

Not the only place I've seen the issue referenced either:

https://stackoverflow.com/questions/69097246/how-to-support-for-windows-11-snap-layout-to-the-custom-maximize-restore-butto

Alkl58/NotEnoughAV1Encodes#91

https://learn.microsoft.com/en-us/answers/questions/625167/unable-to-resize-wpf-windows-by-mouse-when-wndproc

It would be nice to have some accountability on this.

@Greedquest
Copy link

Greedquest commented Oct 19, 2023

Hey folks, Just letting you know that we are still working on this issue internally and will have a response for you soon. We appreciate your patience.

Originally posted by @mevey in #4825 (comment)

I'm still curious about this feature, are there any further updates and is it planned to be progressed? It would make apps feel a lot more professional, right now mine feels "homemade" which isn't what I'm going for:)

@sungaila
Copy link

The default title bar is rubbish and the offers very little options in the way of customisation and theme support. That's why an overwhelming majority of UI libraries have customised the window chrome.

I'd rather stick with the default titlebar if WPF would take care of most boilerplate code. E.g. query the Windows theme settings and to set DWMWA_USE_IMMERSIVE_DARK_MODE (for the native dark themed titlebar) accordingly.

@mortenbrudvik
Copy link

ControlzEx WindowChromeBehavior works like a charm, fully supporting snap layout. I have also created a fully custom window titlebar example based on ControlzEx. code example

@Yari27
Copy link

Yari27 commented Jun 17, 2024

After implementing Snap Layout, styles for the button do not work.
How do I force a button hover and pressed (color) style to be used (for used Triggers in style)?

https://gitlab.com/jplibraries/windowsextensionlibrary/-/blob/master/WindowsExtensionLibrary/MainWindow.xaml.cs

For VisualStateManager work:

VisualStateManager.GoToState(btnMaximizeRestore, "MouseOver", true);
VisualStateManager.GoToState(btnMaximizeRestore, "Normal", true);

@lindexi
Copy link
Member

lindexi commented Jun 17, 2024

@Yari27 I'm sorry, but with limited information, I can't find the answer. Could you attach the solution folder?

@batzen
Copy link
Contributor

batzen commented Jun 17, 2024

It doesn't work because once you return hittest results like maximize the controls no longer receive mouse over events.
ControlzEx solves this by using an additional attached property for nc mouseover.

@Yari27
Copy link

Yari27 commented Jun 17, 2024

@batzen thx, attached property work great.

@SlimeNull
Copy link

SlimeNull commented Jul 4, 2024

I created a library WPF Suite including this feature,process the WM_NCHITTEST message, set the IsMouseOver and IsPressed properties of the control, and correctly trigger the Button's Click event, execute its Command。

It uses reflection to get DependencyPropertyKey of "IsMouseHover" and "IsPressed", then set the value. All styles depends on these properties works well

Here is the document and sample code for using it。
Custom caption menu buttons

image

@augustresende
Copy link

If anyone is interested, flutter needs a way to Snap Layout work when title bar is customized too:
flutter/flutter#156791

@icnahom
Copy link

icnahom commented Oct 15, 2024

@augustresende I believe Electron supports this feature. It'd be worth checking out how they did it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests