Bug 1934040 - Remove WS_SYSMENU when using custom titlebar, so that DWM doesn't draw caption buttons. r=win-reviewers,rkraesig

Unhide our buttons instead, which fixes the caption button sizes when
Mica is enabled.

Crucially (and this is what I had failed to do in my original attempts),
we need to keep WS_MAXIMIZEBOX for Snap Layouts and Aero snap to keep
working. WS_MINIMIZEBOX doesn't hurt either.

This is a bit scary, because we're in undocumented territory, but afaict
(looking with winspy), MS Edge does the same for its custom titlebar, so
I think this is probably safe. It's early in the cycle anyways...

Make the pre-xul skeleton UI flags more consistent while at it.
WS_OVERLAPPED is zero, and WS_SIZEBOX is the same as WS_THICKFRAME (so
there's no change other than removing WS_SYSMENU), but that way it
matches nsWindow::WindowStyle more directly.

In order to not fully lose the system menu functionality, reuse the
functionality we already have to show it on fullscreen windows (which
already lack these styles). Note that this also fixes a bug on which, if
you have a fullscreen window in a non-primary monitor, the system menu
shows up in the primary monitor instead of in your window.

Differential Revision: https://phabricator.services.mozilla.com/D230722
This commit is contained in:
Emilio Cobos Álvarez
2024-12-03 16:51:28 +00:00
parent cebda9b0d0
commit d402fcd892
4 changed files with 89 additions and 69 deletions

View File

@@ -30,16 +30,6 @@
@media (-moz-windows-mica) {
&:not([lwtheme]) {
background-color: transparent;
/* Accent color in titlebar overrides Mica. */
@media not (-moz-windows-accent-color-in-titlebar) {
/* Hide the Firefox buttons since Windows draws their own.
* FIXME(emilio): Find a way of hiding the native buttons, or make them
* taller, this is very hacky. */
.titlebar-buttonbox {
opacity: 0;
}
}
}
}

View File

@@ -21,8 +21,8 @@ namespace mozilla {
// to not vary based off of any user settings for the initial toplevel window,
// so we're safe here for now.
static const DWORD kPreXULSkeletonUIWindowStyle =
WS_CLIPCHILDREN | WS_DLGFRAME | WS_BORDER | WS_MAXIMIZEBOX |
WS_MINIMIZEBOX | WS_SIZEBOX | WS_SYSMENU;
WS_OVERLAPPED | WS_CLIPCHILDREN | WS_DLGFRAME | WS_BORDER | WS_THICKFRAME |
WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU;
static const DWORD kPreXULSkeletonUIWindowStyleEx = WS_EX_WINDOWEDGE;
struct CSSPixelSpan {

View File

@@ -2671,10 +2671,35 @@ void nsWindow::SetCustomTitlebar(bool aCustomTitlebar) {
mCustomNonClient = aCustomTitlebar;
const LONG_PTR style = GetWindowLongPtrW(mWnd, GWL_STYLE);
// Force a reflow of content based on the new client dimensions.
if (mCustomNonClient) {
if (style & WS_SYSMENU) {
// Remove the WS_SYSMENU style, so that DWM doesn't draw the caption
// buttons. Note that we still need WS_MAXIMIZEBOX at least to
// support Snap Layouts / Aero Snap.
//
// This behavior is not documented: per MSDN, WS_MAXIMIZEBOX simply
// requires WS_SYSMENU, and is not valid without it. However, omitting it
// doesn't seem to have negative side-effects on any version of Windows
// tested (other than losing the default system menu handling, which we
// implement ourselves in DisplaySystemMenu()).
//
// Since the system menu is lazily initialized (see [1]), we have to call
// GetSystemMenu() here in order to get it created before it is too late.
// An alternative would be to play with window styles later to force it
// to be created, but that seems a bit more finicky.
//
// [1]: https://devblogs.microsoft.com/oldnewthing/20100528-00/?p=13893
::GetSystemMenu(mWnd, FALSE);
::SetWindowLongPtrW(mWnd, GWL_STYLE, style & ~WS_SYSMENU);
}
UpdateNonClientMargins();
} else {
if (WindowStyle() & WS_SYSMENU) {
// Restore the WS_SYSMENU style if appropriate.
::SetWindowLongPtrW(mWnd, GWL_STYLE, style | WS_SYSMENU);
}
ResetLayout();
}
}
@@ -4498,53 +4523,55 @@ void nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam) {
static bool DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, bool isRtl,
int32_t x, int32_t y) {
HMENU hMenu = GetSystemMenu(hWnd, FALSE);
if (hMenu) {
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE;
mii.fType = 0;
// update the options
mii.fState = MF_ENABLED;
SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
mii.fState = MF_GRAYED;
switch (sizeMode) {
case nsSizeMode_Fullscreen:
// intentional fall through
case nsSizeMode_Maximized:
SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
break;
case nsSizeMode_Minimized:
SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
break;
case nsSizeMode_Normal:
SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
break;
case nsSizeMode_Invalid:
NS_ASSERTION(false, "Did the argument come from invalid IPC?");
break;
default:
MOZ_ASSERT_UNREACHABLE("Unhnalded nsSizeMode value detected");
break;
}
LPARAM cmd = TrackPopupMenu(
hMenu,
(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_TOPALIGN |
(isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
x, y, 0, hWnd, nullptr);
if (cmd) {
PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
return true;
}
if (NS_WARN_IF(!hMenu)) {
return false;
}
return false;
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE;
mii.fType = 0;
// update the options
mii.fState = MF_ENABLED;
SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
mii.fState = MF_GRAYED;
switch (sizeMode) {
case nsSizeMode_Fullscreen:
// intentional fall through
case nsSizeMode_Maximized:
SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
break;
case nsSizeMode_Minimized:
SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
break;
case nsSizeMode_Normal:
SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
break;
case nsSizeMode_Invalid:
NS_ASSERTION(false, "Did the argument come from invalid IPC?");
break;
default:
MOZ_ASSERT_UNREACHABLE("Unhnalded nsSizeMode value detected");
break;
}
LPARAM cmd = TrackPopupMenu(hMenu,
TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD |
TPM_TOPALIGN |
(isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN),
x, y, 0, hWnd, nullptr);
if (!cmd) {
return false;
}
PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
return true;
}
// The WndProc procedure for all nsWindows in this toolkit. This merely catches
@@ -5700,13 +5727,20 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
result = true;
}
// Handle the system menu manually when we're in full screen mode
// so we can set the appropriate options.
if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE &&
mFrameState->GetSizeMode() == nsSizeMode_Fullscreen) {
DisplaySystemMenu(mWnd, mFrameState->GetSizeMode(), mIsRTL,
MOZ_SYSCONTEXT_X_POS, MOZ_SYSCONTEXT_Y_POS);
result = true;
if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE) {
const auto sizeMode = mFrameState->GetSizeMode();
// Handle the system menu manually when we're in full screen mode or
// with custom titlebar so we can set the appropriate options.
if (sizeMode == nsSizeMode_Fullscreen || mCustomNonClient) {
// Historically on fullscreen windows we've used this offset from the
// top left as our context menu position. Note that if the point we
// supply is offscreen, Windows will still try to put our menu in the
// right place.
constexpr LayoutDeviceIntPoint offset(20, 20);
auto pos = GetScreenBounds().TopLeft() + offset;
DisplaySystemMenu(mWnd, sizeMode, mIsRTL, pos.x, pos.y);
result = true;
}
}
} break;

View File

@@ -24,10 +24,6 @@
// ConstrainPosition window positioning slop value
#define kWindowPositionSlop 20
// Origin of the system context menu when displayed in full screen mode
#define MOZ_SYSCONTEXT_X_POS 20
#define MOZ_SYSCONTEXT_Y_POS 20
// Don't put more than this many rects in the dirty region, just fluff
// out to the bounding-box if there are more
#define MAX_RECTS_IN_REGION 100