Bug 1878037 - Fix some regressions on alert windows. r=saschanaz,win-reviewers,rkraesig

Bug 1870512 removed top level windows with WindowType::Popup, instead
replacing it with an "alert" feature for the only use of them that we
had.

Turns out that on Windows they need a bit more special handling than I
thought, so this patch uses the alert boolean to fix two regressions
(that alerts now create taskbar icons, and that they steal focus).

Remove mIsForMenuPopupFrame since that is now a synonym with
WindowType::Popup.

Remove also the dialog vs. toplevel difference of using
WS_EX_DLGMODALFRAME, since that doesn't seem to have an effect at all on
windows 10+.

Differential Revision: https://phabricator.services.mozilla.com/D200508
This commit is contained in:
Emilio Cobos Álvarez 2024-02-12 19:45:48 +00:00
parent 0a93c03ada
commit f56dca9254
5 changed files with 40 additions and 30 deletions

View file

@ -268,7 +268,6 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
widget::InitData widgetData; widget::InitData widgetData;
widgetData.mWindowType = widget::WindowType::Popup; widgetData.mWindowType = widget::WindowType::Popup;
widgetData.mBorderStyle = widget::BorderStyle::Default; widgetData.mBorderStyle = widget::BorderStyle::Default;
widgetData.mForMenupopupFrame = true;
widgetData.mClipSiblings = true; widgetData.mClipSiblings = true;
widgetData.mPopupHint = mPopupType; widgetData.mPopupHint = mPopupType;
widgetData.mNoAutoHide = IsNoAutoHide(); widgetData.mNoAutoHide = IsNoAutoHide();

View file

@ -91,7 +91,6 @@ struct InitData {
// when painting exclude area occupied by child windows and sibling windows // when painting exclude area occupied by child windows and sibling windows
bool mClipChildren = false; bool mClipChildren = false;
bool mClipSiblings = false; bool mClipSiblings = false;
bool mForMenupopupFrame = false;
bool mRTL = false; bool mRTL = false;
bool mNoAutoHide = false; // true for noautohide panels bool mNoAutoHide = false; // true for noautohide panels
bool mIsDragPopup = false; // true for drag feedback panels bool mIsDragPopup = false; // true for drag feedback panels

View file

@ -868,9 +868,9 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
} }
mIsRTL = aInitData->mRTL; mIsRTL = aInitData->mRTL;
mForMenupopupFrame = aInitData->mForMenupopupFrame;
mOpeningAnimationSuppressed = aInitData->mIsAnimationSuppressed; mOpeningAnimationSuppressed = aInitData->mIsAnimationSuppressed;
mAlwaysOnTop = aInitData->mAlwaysOnTop; mAlwaysOnTop = aInitData->mAlwaysOnTop;
mIsAlert = aInitData->mIsAlert;
mResizable = aInitData->mResizable; mResizable = aInitData->mResizable;
DWORD style = WindowStyle(); DWORD style = WindowStyle();
@ -895,7 +895,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
} }
} }
const wchar_t* className = ChooseWindowClass(mWindowType, mForMenupopupFrame); const wchar_t* className = ChooseWindowClass(mWindowType);
// Take specific actions when creating the first top-level window // Take specific actions when creating the first top-level window
static bool sFirstTopLevelWindowCreated = false; static bool sFirstTopLevelWindowCreated = false;
@ -1220,20 +1220,15 @@ const wchar_t* nsWindow::RegisterWindowClass(const wchar_t* aClassName,
static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512); static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
/* static */ /* static */
const wchar_t* nsWindow::ChooseWindowClass(WindowType aWindowType, const wchar_t* nsWindow::ChooseWindowClass(WindowType aWindowType) {
bool aForMenupopupFrame) {
MOZ_ASSERT_IF(aForMenupopupFrame, aWindowType == WindowType::Popup);
switch (aWindowType) { switch (aWindowType) {
case WindowType::Invisible: case WindowType::Invisible:
return RegisterWindowClass(kClassNameHidden, 0, gStockApplicationIcon); return RegisterWindowClass(kClassNameHidden, 0, gStockApplicationIcon);
case WindowType::Dialog: case WindowType::Dialog:
return RegisterWindowClass(kClassNameDialog, 0, 0); return RegisterWindowClass(kClassNameDialog, 0, 0);
case WindowType::Popup: case WindowType::Popup:
if (aForMenupopupFrame) {
return RegisterWindowClass(kClassNameDropShadow, CS_DROPSHADOW, return RegisterWindowClass(kClassNameDropShadow, CS_DROPSHADOW,
gStockApplicationIcon); gStockApplicationIcon);
}
[[fallthrough]];
default: default:
return RegisterWindowClass(GetMainWindowClass(), 0, return RegisterWindowClass(GetMainWindowClass(), 0,
gStockApplicationIcon); gStockApplicationIcon);
@ -1341,22 +1336,27 @@ DWORD nsWindow::WindowExStyle() {
case WindowType::Child: case WindowType::Child:
return 0; return 0;
case WindowType::Dialog:
return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
case WindowType::Popup: { case WindowType::Popup: {
DWORD extendedStyle = WS_EX_TOOLWINDOW; DWORD extendedStyle = WS_EX_TOOLWINDOW;
if (mPopupLevel == PopupLevel::Top) extendedStyle |= WS_EX_TOPMOST; if (mPopupLevel == PopupLevel::Top) {
extendedStyle |= WS_EX_TOPMOST;
}
return extendedStyle; return extendedStyle;
} }
default:
NS_ERROR("unknown border style");
[[fallthrough]];
case WindowType::Sheet:
MOZ_FALLTHROUGH_ASSERT("Sheets are macOS specific");
case WindowType::Dialog:
case WindowType::TopLevel: case WindowType::TopLevel:
case WindowType::Invisible: case WindowType::Invisible:
return WS_EX_WINDOWEDGE; break;
} }
if (mIsAlert) {
MOZ_ASSERT(mWindowType == WindowType::Dialog,
"Expect alert windows to have type=dialog");
return WS_EX_TOOLWINDOW;
}
return WS_EX_WINDOWEDGE;
} }
/************************************************************** /**************************************************************
@ -1575,9 +1575,8 @@ void nsWindow::Show(bool bState) {
#endif // defined(ACCESSIBILITY) #endif // defined(ACCESSIBILITY)
} }
if (mForMenupopupFrame) { if (mWindowType == WindowType::Popup) {
MOZ_ASSERT(ChooseWindowClass(mWindowType, mForMenupopupFrame) == MOZ_ASSERT(ChooseWindowClass(mWindowType) == kClassNameDropShadow);
kClassNameDropShadow);
const bool shouldUseDropShadow = const bool shouldUseDropShadow =
mTransparencyMode != TransparencyMode::Transparent; mTransparencyMode != TransparencyMode::Transparent;
@ -1644,8 +1643,12 @@ void nsWindow::Show(bool bState) {
} }
} else { } else {
DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW; DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
if (wasVisible) flags |= SWP_NOZORDER; if (wasVisible) {
if (mAlwaysOnTop) flags |= SWP_NOACTIVATE; flags |= SWP_NOZORDER;
}
if (mAlwaysOnTop || mIsAlert) {
flags |= SWP_NOACTIVATE;
}
if (mWindowType == WindowType::Popup) { if (mWindowType == WindowType::Popup) {
// ensure popups are the topmost of the TOPMOST // ensure popups are the topmost of the TOPMOST
@ -7858,7 +7861,7 @@ bool nsWindow::DealWithPopups(HWND aWnd, UINT aMessage, WPARAM aWParam,
// because we cannot distinguish it's caused by mouse or not. // because we cannot distinguish it's caused by mouse or not.
if (LOWORD(aWParam) == WA_ACTIVE && aLParam) { if (LOWORD(aWParam) == WA_ACTIVE && aLParam) {
nsWindow* window = WinUtils::GetNSWindowPtr(aWnd); nsWindow* window = WinUtils::GetNSWindowPtr(aWnd);
if (window && window->IsPopup()) { if (window && (window->IsPopup() || window->mIsAlert)) {
// Cancel notifying widget listeners of deactivating the previous // Cancel notifying widget listeners of deactivating the previous
// active window (see WM_KILLFOCUS case in ProcessMessage()). // active window (see WM_KILLFOCUS case in ProcessMessage()).
sJustGotDeactivate = false; sJustGotDeactivate = false;

View file

@ -593,7 +593,7 @@ class nsWindow final : public nsBaseWidget {
DWORD WindowStyle(); DWORD WindowStyle();
DWORD WindowExStyle(); DWORD WindowExStyle();
static const wchar_t* ChooseWindowClass(WindowType, bool aForMenupopupFrame); static const wchar_t* ChooseWindowClass(WindowType);
// This method registers the given window class, and returns the class name. // This method registers the given window class, and returns the class name.
static const wchar_t* RegisterWindowClass(const wchar_t* aClassName, static const wchar_t* RegisterWindowClass(const wchar_t* aClassName,
UINT aExtraStyle, LPWSTR aIconID); UINT aExtraStyle, LPWSTR aIconID);
@ -754,7 +754,10 @@ class nsWindow final : public nsBaseWidget {
bool mIsEarlyBlankWindow = false; bool mIsEarlyBlankWindow = false;
bool mIsShowingPreXULSkeletonUI = false; bool mIsShowingPreXULSkeletonUI = false;
bool mResizable = false; bool mResizable = false;
bool mForMenupopupFrame = false; // Whether we're an alert window. Alert windows don't have taskbar icons and
// don't steal focus from other windows when opened. They're also expected to
// be of type WindowType::Dialog.
bool mIsAlert = false;
bool mIsPerformingDwmFlushHack = false; bool mIsPerformingDwmFlushHack = false;
bool mDraggingWindowWithMouse = false; bool mDraggingWindowWithMouse = false;
DWORD_PTR mOldStyle = 0; DWORD_PTR mOldStyle = 0;
@ -835,7 +838,7 @@ class nsWindow final : public nsBaseWidget {
// Whether we're in the process of sending a WM_SETTEXT ourselves // Whether we're in the process of sending a WM_SETTEXT ourselves
bool mSendingSetText = false; bool mSendingSetText = false;
// Whether we we're created as a child window (aka ChildWindow) or not. // Whether we were created as a child window (aka ChildWindow) or not.
bool mIsChildWindow : 1; bool mIsChildWindow : 1;
int32_t mCachedHitTestResult = 0; int32_t mCachedHitTestResult = 0;

View file

@ -571,7 +571,13 @@ nsresult nsAppShellService::JustCreateTopWindow(
} }
#endif #endif
widgetInitData.mIsAlert = !!(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT); // alert=yes is expected to be used along with dialogs, not other window
// types.
MOZ_ASSERT_IF(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT,
widgetInitData.mWindowType == widget::WindowType::Dialog);
widgetInitData.mIsAlert =
!!(aChromeMask & nsIWebBrowserChrome::CHROME_ALERT) &&
widgetInitData.mWindowType == widget::WindowType::Dialog;
#ifdef XP_MACOSX #ifdef XP_MACOSX
// Mac OS X sheet support // Mac OS X sheet support