Bug 1811487 - Clean-up popup hide / rollup APIs. r=cmartin

I'm about to extend them for bug 1811486, where I want to force in some
cases the rolled up popups to hide synchronously. These APIs use a ton
of boolean arguments that make them error prone, so refactor them a bit
to use strongly typed enums and flags.

Differential Revision: https://phabricator.services.mozilla.com/D167381
This commit is contained in:
Emilio Cobos Álvarez 2023-01-23 11:58:25 +00:00
Родитель f525107cb0
Коммит 5c3fc07c2e
18 изменённых файлов: 217 добавлений и 189 удалений

Просмотреть файл

@ -95,9 +95,9 @@ void XULButtonElement::HandleEnterKeyPress(WidgetEvent& aEvent) {
#ifdef XP_WIN #ifdef XP_WIN
if (XULPopupElement* popup = GetContainingPopupElement()) { if (XULPopupElement* popup = GetContainingPopupElement()) {
if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
pm->HidePopup(popup, /* aHideChain = */ true, pm->HidePopup(
/* aDeselectMenu = */ true, /* aAsynchronous = */ true, popup, {HidePopupOption::HideChain, HidePopupOption::DeselectMenu,
/* aIsCancel = */ false); HidePopupOption::Async});
} }
} }
#endif #endif
@ -211,7 +211,11 @@ void XULButtonElement::CloseMenuPopup(bool aDeselectMenu) {
return; return;
} }
if (auto* popup = GetMenuPopupContent()) { if (auto* popup = GetMenuPopupContent()) {
pm->HidePopup(popup, false, aDeselectMenu, true, false); HidePopupOptions options{HidePopupOption::Async};
if (aDeselectMenu) {
options += HidePopupOption::DeselectMenu;
}
pm->HidePopup(popup, options);
} }
} }

Просмотреть файл

@ -106,9 +106,14 @@ void XULPopupElement::OpenPopupAtScreenRect(const nsAString& aPosition,
void XULPopupElement::HidePopup(bool aCancel) { void XULPopupElement::HidePopup(bool aCancel) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) { if (!pm) {
pm->HidePopup(this, false, true, false, aCancel); return;
} }
HidePopupOptions options{HidePopupOption::DeselectMenu};
if (aCancel) {
options += HidePopupOption::IsRollup;
}
pm->HidePopup(this, options);
} }
static Modifiers ConvertModifiers(const ActivateMenuItemOptions& aModifiers) { static Modifiers ConvertModifiers(const ActivateMenuItemOptions& aModifiers) {

Просмотреть файл

@ -170,7 +170,9 @@ void nsXULPopupListener::ClosePopup() {
// popup is hidden. Use asynchronous hiding just to be safe so we don't // popup is hidden. Use asynchronous hiding just to be safe so we don't
// fire events during destruction. // fire events during destruction.
nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) pm->HidePopup(mPopupContent, false, true, true, false); if (pm)
pm->HidePopup(mPopupContent,
{HidePopupOption::DeselectMenu, HidePopupOption::Async});
mPopupContent = nullptr; // release the popup mPopupContent = nullptr; // release the popup
} }
} // ClosePopup } // ClosePopup

Просмотреть файл

@ -207,7 +207,7 @@ nsresult nsMenuBarListener::KeyUp(Event* aKeyEvent) {
// handle key events when menubar is active and IME should be // handle key events when menubar is active and IME should be
// disabled. // disabled.
if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
pm->Rollup(0, false, nullptr, nullptr); pm->Rollup({});
} }
// If menubar active state is changed or the menubar is destroyed // If menubar active state is changed or the menubar is destroyed
// during closing the popups, we should do nothing anymore. // during closing the popups, we should do nothing anymore.

Просмотреть файл

@ -62,6 +62,7 @@
#include <algorithm> #include <algorithm>
#include "X11UndefineNone.h" #include "X11UndefineNone.h"
#include "nsXULPopupManager.h"
using namespace mozilla; using namespace mozilla;
using mozilla::dom::Document; using mozilla::dom::Document;
@ -2463,7 +2464,8 @@ void nsMenuPopupFrame::CheckForAnchorChange(nsRect& aRect) {
if (pm) { if (pm) {
// As the caller will be iterating over the open popups, hide // As the caller will be iterating over the open popups, hide
// asyncronously. // asyncronously.
pm->HidePopup(mContent, false, true, true, false); pm->HidePopup(mContent,
{HidePopupOption::DeselectMenu, HidePopupOption::Async});
} }
return; return;

Просмотреть файл

@ -278,14 +278,12 @@ nsXULPopupManager* nsXULPopupManager::GetInstance() {
} }
bool nsXULPopupManager::RollupTooltips() { bool nsXULPopupManager::RollupTooltips() {
return RollupInternal(RollupKind::Tooltip, UINT32_MAX, false, nullptr, return RollupInternal(RollupKind::Tooltip, {}, nullptr);
nullptr);
} }
bool nsXULPopupManager::Rollup(uint32_t aCount, bool aFlush, bool nsXULPopupManager::Rollup(const RollupOptions& aOptions,
const LayoutDeviceIntPoint* aPos,
nsIContent** aLastRolledUp) { nsIContent** aLastRolledUp) {
return RollupInternal(RollupKind::Menu, aCount, aFlush, aPos, aLastRolledUp); return RollupInternal(RollupKind::Menu, aOptions, aLastRolledUp);
} }
bool nsXULPopupManager::RollupNativeMenu() { bool nsXULPopupManager::RollupNativeMenu() {
@ -296,9 +294,8 @@ bool nsXULPopupManager::RollupNativeMenu() {
return false; return false;
} }
bool nsXULPopupManager::RollupInternal(RollupKind aKind, uint32_t aCount, bool nsXULPopupManager::RollupInternal(RollupKind aKind,
bool aFlush, const RollupOptions& aOptions,
const LayoutDeviceIntPoint* pos,
nsIContent** aLastRolledUp) { nsIContent** aLastRolledUp) {
if (aLastRolledUp) { if (aLastRolledUp) {
*aLastRolledUp = nullptr; *aLastRolledUp = nullptr;
@ -349,7 +346,7 @@ bool nsXULPopupManager::RollupInternal(RollupKind aKind, uint32_t aCount,
// This would be used to allow adjusting the caret position in an // This would be used to allow adjusting the caret position in an
// autocomplete field without hiding the popup for example. // autocomplete field without hiding the popup for example.
bool noRollupOnAnchor = bool noRollupOnAnchor =
(!consume && pos && (!consume && aOptions.mPoint &&
item->Frame()->GetContent()->AsElement()->AttrValueIs( item->Frame()->GetContent()->AsElement()->AttrValueIs(
kNameSpaceID_None, nsGkAtoms::norolluponanchor, nsGkAtoms::_true, kNameSpaceID_None, nsGkAtoms::norolluponanchor, nsGkAtoms::_true,
eCaseMatters)); eCaseMatters));
@ -358,7 +355,7 @@ bool nsXULPopupManager::RollupInternal(RollupKind aKind, uint32_t aCount,
// when the click was over the anchor. This way, clicking on a menu doesn't // when the click was over the anchor. This way, clicking on a menu doesn't
// reopen the menu. // reopen the menu.
if ((consumeResult == ConsumeOutsideClicks_ParentOnly || noRollupOnAnchor) && if ((consumeResult == ConsumeOutsideClicks_ParentOnly || noRollupOnAnchor) &&
pos) { aOptions.mPoint) {
nsMenuPopupFrame* popupFrame = item->Frame(); nsMenuPopupFrame* popupFrame = item->Frame();
CSSIntRect anchorRect = [&] { CSSIntRect anchorRect = [&] {
if (popupFrame->IsAnchored()) { if (popupFrame->IsAnchored()) {
@ -399,7 +396,8 @@ bool nsXULPopupManager::RollupInternal(RollupKind aKind, uint32_t aCount,
// event will get consumed, so here only a quick coordinates check is // event will get consumed, so here only a quick coordinates check is
// done rather than a slower complete check of what is at that location. // done rather than a slower complete check of what is at that location.
nsPresContext* presContext = item->Frame()->PresContext(); nsPresContext* presContext = item->Frame()->PresContext();
CSSIntPoint posCSSPixels = presContext->DevPixelsToIntCSSPixels(*pos); CSSIntPoint posCSSPixels =
presContext->DevPixelsToIntCSSPixels(*aOptions.mPoint);
if (anchorRect.Contains(posCSSPixels)) { if (anchorRect.Contains(posCSSPixels)) {
if (consumeResult == ConsumeOutsideClicks_ParentOnly) { if (consumeResult == ConsumeOutsideClicks_ParentOnly) {
consume = true; consume = true;
@ -415,12 +413,13 @@ bool nsXULPopupManager::RollupInternal(RollupKind aKind, uint32_t aCount,
return false; return false;
} }
// if a number of popups to close has been specified, determine the last // If a number of popups to close has been specified, determine the last
// popup to close // popup to close.
nsIContent* lastPopup = nullptr; nsIContent* lastPopup = nullptr;
if (aCount != UINT32_MAX) { uint32_t count = aOptions.mCount;
if (count && count != UINT32_MAX) {
nsMenuChainItem* last = item; nsMenuChainItem* last = item;
while (--aCount && last->GetParent()) { while (--count && last->GetParent()) {
last = last->GetParent(); last = last->GetParent();
} }
if (last) { if (last) {
@ -432,9 +431,12 @@ bool nsXULPopupManager::RollupInternal(RollupKind aKind, uint32_t aCount,
RefPtr<nsViewManager> viewManager = RefPtr<nsViewManager> viewManager =
presContext->PresShell()->GetViewManager(); presContext->PresShell()->GetViewManager();
HidePopup(item->Content(), true, true, false, true, lastPopup); HidePopup(item->Content(),
{HidePopupOption::HideChain, HidePopupOption::DeselectMenu,
HidePopupOption::IsRollup},
lastPopup);
if (aFlush) { if (aOptions.mFlush == FlushViews::Yes) {
// The popup's visibility doesn't update until the minimize animation // The popup's visibility doesn't update until the minimize animation
// has finished, so call UpdateWidgetGeometry to update it right away. // has finished, so call UpdateWidgetGeometry to update it right away.
viewManager->UpdateWidgetGeometry(); viewManager->UpdateWidgetGeometry();
@ -944,7 +946,7 @@ void nsXULPopupManager::OnNativeMenuClosed() {
// menus. // menus.
// Close the non-native menus now. This matches the HidePopup call in // Close the non-native menus now. This matches the HidePopup call in
// nsXULMenuCommandEvent::Run. // nsXULMenuCommandEvent::Run.
HidePopup(mPopups->Content(), true, false, false, false); HidePopup(mPopups->Content(), {HidePopupOption::HideChain});
} }
} }
@ -1130,9 +1132,8 @@ nsMenuChainItem* nsXULPopupManager::FindPopup(nsIContent* aPopup) const {
return nullptr; return nullptr;
} }
void nsXULPopupManager::HidePopup(nsIContent* aPopup, bool aHideChain, void nsXULPopupManager::HidePopup(nsIContent* aPopup, HidePopupOptions aOptions,
bool aDeselectMenu, bool aAsynchronous, nsIContent* aLastPopup) {
bool aIsCancel, nsIContent* aLastPopup) {
if (mNativeMenu && mNativeMenu->Element() == aPopup) { if (mNativeMenu && mNativeMenu->Element() == aPopup) {
RefPtr<NativeMenu> menu = mNativeMenu; RefPtr<NativeMenu> menu = mNativeMenu;
(void)menu->Close(); (void)menu->Close();
@ -1146,7 +1147,6 @@ void nsXULPopupManager::HidePopup(nsIContent* aPopup, bool aHideChain,
nsMenuChainItem* foundPopup = FindPopup(aPopup); nsMenuChainItem* foundPopup = FindPopup(aPopup);
bool deselectMenu = false;
nsCOMPtr<nsIContent> popupToHide, nextPopup, lastPopup; nsCOMPtr<nsIContent> popupToHide, nextPopup, lastPopup;
if (foundPopup) { if (foundPopup) {
@ -1154,6 +1154,8 @@ void nsXULPopupManager::HidePopup(nsIContent* aPopup, bool aHideChain,
// If this is a noautohide panel, remove it but don't close any other // If this is a noautohide panel, remove it but don't close any other
// panels. // panels.
popupToHide = aPopup; popupToHide = aPopup;
// XXX This preserves behavior but why is it the right thing to do?
aOptions -= HidePopupOption::DeselectMenu;
} else { } else {
// At this point, foundPopup will be set to the found item in the list. If // At this point, foundPopup will be set to the found item in the list. If
// foundPopup is the topmost menu, the one to remove, then there are no // foundPopup is the topmost menu, the one to remove, then there are no
@ -1183,14 +1185,15 @@ void nsXULPopupManager::HidePopup(nsIContent* aPopup, bool aHideChain,
} }
} }
deselectMenu = aDeselectMenu;
popupToHide = topMenu->Content(); popupToHide = topMenu->Content();
popupFrame = topMenu->Frame(); popupFrame = topMenu->Frame();
const bool hideChain = aOptions.contains(HidePopupOption::HideChain);
// Close up another popup if there is one, and we are either hiding the // Close up another popup if there is one, and we are either hiding the
// entire chain or the item to hide isn't the topmost popup. // entire chain or the item to hide isn't the topmost popup.
nsMenuChainItem* parent = topMenu->GetParent(); nsMenuChainItem* parent = topMenu->GetParent();
if (parent && (aHideChain || topMenu != foundPopup)) { if (parent && (hideChain || topMenu != foundPopup)) {
while (parent && parent->IsNoAutoHide()) { while (parent && parent->IsNoAutoHide()) {
parent = parent->GetParent(); parent = parent->GetParent();
} }
@ -1200,17 +1203,19 @@ void nsXULPopupManager::HidePopup(nsIContent* aPopup, bool aHideChain,
} }
} }
lastPopup = aLastPopup ? aLastPopup : (aHideChain ? nullptr : aPopup); lastPopup = aLastPopup ? aLastPopup : (hideChain ? nullptr : aPopup);
} }
} else if (popupFrame->PopupState() == ePopupPositioning) { } else if (popupFrame->PopupState() == ePopupPositioning) {
// When the popup is in the popuppositioning state, it will not be in the // When the popup is in the popuppositioning state, it will not be in the
// mPopups list. We need another way to find it and make sure it does not // mPopups list. We need another way to find it and make sure it does not
// continue the popup showing process. // continue the popup showing process.
deselectMenu = aDeselectMenu;
popupToHide = aPopup; popupToHide = aPopup;
} }
if (popupToHide) { if (!popupToHide) {
return;
}
nsPopupState state = popupFrame->PopupState(); nsPopupState state = popupFrame->PopupState();
// If the popup is already being hidden, don't attempt to hide it again // If the popup is already being hidden, don't attempt to hide it again
if (state == ePopupHiding) { if (state == ePopupHiding) {
@ -1225,16 +1230,14 @@ void nsXULPopupManager::HidePopup(nsIContent* aPopup, bool aHideChain,
} }
// For menus, popupToHide is always the frontmost item in the list to hide. // For menus, popupToHide is always the frontmost item in the list to hide.
if (aAsynchronous) { if (aOptions.contains(HidePopupOption::Async)) {
nsCOMPtr<nsIRunnable> event = new nsXULPopupHidingEvent( nsCOMPtr<nsIRunnable> event = new nsXULPopupHidingEvent(
popupToHide, nextPopup, lastPopup, popupFrame->PopupType(), popupToHide, nextPopup, lastPopup, popupFrame->PopupType(), aOptions);
deselectMenu, aIsCancel);
aPopup->OwnerDoc()->Dispatch(TaskCategory::Other, event.forget()); aPopup->OwnerDoc()->Dispatch(TaskCategory::Other, event.forget());
} else { } else {
RefPtr<nsPresContext> presContext = popupFrame->PresContext(); RefPtr<nsPresContext> presContext = popupFrame->PresContext();
FirePopupHidingEvent(popupToHide, nextPopup, lastPopup, presContext, FirePopupHidingEvent(popupToHide, nextPopup, lastPopup, presContext,
popupFrame->PopupType(), deselectMenu, aIsCancel); popupFrame->PopupType(), aOptions);
}
} }
} }
@ -1253,7 +1256,7 @@ void nsXULPopupManager::HideMenu(nsIContent* aMenu) {
if (!popup) { if (!popup) {
return; return;
} }
HidePopup(popup, false, true, false, false); HidePopup(popup, {HidePopupOption::DeselectMenu});
} }
// This is used to hide the popup after a transition finishes. // This is used to hide the popup after a transition finishes.
@ -1266,13 +1269,13 @@ class TransitionEnder final : public nsIDOMEventListener {
virtual ~TransitionEnder() = default; virtual ~TransitionEnder() = default;
public: public:
bool mDeselectMenu; HidePopupOptions mOptions;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(TransitionEnder) NS_DECL_CYCLE_COLLECTION_CLASS(TransitionEnder)
TransitionEnder(nsIContent* aContent, bool aDeselectMenu) TransitionEnder(nsIContent* aContent, HidePopupOptions aOptions)
: mContent(aContent), mDeselectMenu(aDeselectMenu) {} : mContent(aContent), mOptions(aOptions) {}
MOZ_CAN_RUN_SCRIPT NS_IMETHOD HandleEvent(Event* aEvent) override { MOZ_CAN_RUN_SCRIPT NS_IMETHOD HandleEvent(Event* aEvent) override {
mContent->RemoveSystemEventListener(u"transitionend"_ns, this, false); mContent->RemoveSystemEventListener(u"transitionend"_ns, this, false);
@ -1287,7 +1290,7 @@ class TransitionEnder final : public nsIDOMEventListener {
// the first one ending. // the first one ending.
if (RefPtr<nsXULPopupManager> pm = nsXULPopupManager::GetInstance()) { if (RefPtr<nsXULPopupManager> pm = nsXULPopupManager::GetInstance()) {
pm->HidePopupCallback(mContent, popupFrame, nullptr, nullptr, pm->HidePopupCallback(mContent, popupFrame, nullptr, nullptr,
popupFrame->PopupType(), mDeselectMenu); popupFrame->PopupType(), mOptions);
} }
return NS_OK; return NS_OK;
@ -1304,7 +1307,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION(TransitionEnder, mContent); NS_IMPL_CYCLE_COLLECTION(TransitionEnder, mContent);
void nsXULPopupManager::HidePopupCallback( void nsXULPopupManager::HidePopupCallback(
nsIContent* aPopup, nsMenuPopupFrame* aPopupFrame, nsIContent* aNextPopup, nsIContent* aPopup, nsMenuPopupFrame* aPopupFrame, nsIContent* aNextPopup,
nsIContent* aLastPopup, nsPopupType aPopupType, bool aDeselectMenu) { nsIContent* aLastPopup, nsPopupType aPopupType, HidePopupOptions aOptions) {
if (mCloseTimer && mTimerMenu == aPopupFrame) { if (mCloseTimer && mTimerMenu == aPopupFrame) {
mCloseTimer->Cancel(); mCloseTimer->Cancel();
mCloseTimer = nullptr; mCloseTimer = nullptr;
@ -1325,7 +1328,8 @@ void nsXULPopupManager::HidePopupCallback(
} }
AutoWeakFrame weakFrame(aPopupFrame); AutoWeakFrame weakFrame(aPopupFrame);
aPopupFrame->HidePopup(aDeselectMenu, ePopupClosed); aPopupFrame->HidePopup(aOptions.contains(HidePopupOption::DeselectMenu),
ePopupClosed);
NS_ENSURE_TRUE_VOID(weakFrame.IsAlive()); NS_ENSURE_TRUE_VOID(weakFrame.IsAlive());
// send the popuphidden event synchronously. This event has no default // send the popuphidden event synchronously. This event has no default
@ -1363,7 +1367,7 @@ void nsXULPopupManager::HidePopupCallback(
RefPtr<nsPresContext> presContext = popupFrame->PresContext(); RefPtr<nsPresContext> presContext = popupFrame->PresContext();
FirePopupHidingEvent(popupToHide, nextPopup, aLastPopup, presContext, FirePopupHidingEvent(popupToHide, nextPopup, aLastPopup, presContext,
foundMenu->PopupType(), aDeselectMenu, false); foundMenu->PopupType(), aOptions);
} }
} }
} }
@ -1620,10 +1624,12 @@ void nsXULPopupManager::BeginShowingPopup(const PendingPopup& aPendingPopup,
} }
} }
void nsXULPopupManager::FirePopupHidingEvent( void nsXULPopupManager::FirePopupHidingEvent(nsIContent* aPopup,
nsIContent* aPopup, nsIContent* aNextPopup, nsIContent* aLastPopup, nsIContent* aNextPopup,
nsPresContext* aPresContext, nsPopupType aPopupType, bool aDeselectMenu, nsIContent* aLastPopup,
bool aIsCancel) { nsPresContext* aPresContext,
nsPopupType aPopupType,
HidePopupOptions aOptions) {
nsCOMPtr<nsIContent> popup = aPopup; nsCOMPtr<nsIContent> popup = aPopup;
RefPtr<PresShell> presShell = aPresContext->PresShell(); RefPtr<PresShell> presShell = aPresContext->PresShell();
Unused << presShell; // This presShell may be keeping things alive Unused << presShell; // This presShell may be keeping things alive
@ -1694,7 +1700,8 @@ void nsXULPopupManager::FirePopupHidingEvent(
} }
// If animate="cancel", only show the transition if cancelling the popup // If animate="cancel", only show the transition if cancelling the popup
// or rolling up. // or rolling up.
if (animate.EqualsLiteral("cancel") && !aIsCancel) { if (animate.EqualsLiteral("cancel") &&
!aOptions.contains(HidePopupOption::IsRollup)) {
return false; return false;
} }
return true; return true;
@ -1705,13 +1712,13 @@ void nsXULPopupManager::FirePopupHidingEvent(
// view will be hidden and you won't be able to see it. // view will be hidden and you won't be able to see it.
if (shouldAnimate && AnimationUtils::HasCurrentTransitions( if (shouldAnimate && AnimationUtils::HasCurrentTransitions(
aPopup->AsElement(), PseudoStyleType::NotPseudo)) { aPopup->AsElement(), PseudoStyleType::NotPseudo)) {
RefPtr<TransitionEnder> ender = new TransitionEnder(aPopup, aDeselectMenu); RefPtr<TransitionEnder> ender = new TransitionEnder(aPopup, aOptions);
aPopup->AddSystemEventListener(u"transitionend"_ns, ender, false, false); aPopup->AddSystemEventListener(u"transitionend"_ns, ender, false, false);
return; return;
} }
HidePopupCallback(aPopup, popupFrame, aNextPopup, aLastPopup, aPopupType, HidePopupCallback(aPopup, popupFrame, aNextPopup, aLastPopup, aPopupType,
aDeselectMenu); aOptions);
} }
bool nsXULPopupManager::IsPopupOpen(nsIContent* aPopup) { bool nsXULPopupManager::IsPopupOpen(nsIContent* aPopup) {
@ -1933,7 +1940,7 @@ void nsXULPopupManager::PopupDestroyed(nsMenuPopupFrame* aPopup) {
} else { } else {
// HidePopup will take care of hiding any of its children, so // HidePopup will take care of hiding any of its children, so
// break out afterwards // break out afterwards
HidePopup(child->Content(), false, false, true, false); HidePopup(child->Content(), {HidePopupOption::Async});
break; break;
} }
} }
@ -2135,7 +2142,7 @@ void nsXULPopupManager::KillMenuTimer() {
mCloseTimer = nullptr; mCloseTimer = nullptr;
if (mTimerMenu->IsOpen()) { if (mTimerMenu->IsOpen()) {
HidePopup(mTimerMenu->GetContent(), false, false, true, false); HidePopup(mTimerMenu->GetContent(), {HidePopupOption::Async});
} }
} }
@ -2372,9 +2379,7 @@ bool nsXULPopupManager::HandleKeyboardNavigationInPopup(
// close a submenu when Left is pressed // close a submenu when Left is pressed
if (nsMenuPopupFrame* popupFrame = if (nsMenuPopupFrame* popupFrame =
currentItem->GetMenuPopup(FlushType::None)) { currentItem->GetMenuPopup(FlushType::None)) {
HidePopup(popupFrame->GetContent(), /* aHideChain = */ false, HidePopup(popupFrame->GetContent(), {});
/* aDeselectMenu = */ false, /* aAsynchronous = */ false,
/* aIsCancel = */ false);
} }
return true; return true;
} }
@ -2390,7 +2395,7 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
if (aTopVisibleMenuItem && if (aTopVisibleMenuItem &&
aTopVisibleMenuItem->PopupType() != ePopupTypeMenu) { aTopVisibleMenuItem->PopupType() != ePopupTypeMenu) {
if (keyCode == KeyboardEvent_Binding::DOM_VK_ESCAPE) { if (keyCode == KeyboardEvent_Binding::DOM_VK_ESCAPE) {
HidePopup(aTopVisibleMenuItem->Content(), false, false, false, true); HidePopup(aTopVisibleMenuItem->Content(), {HidePopupOption::IsRollup});
aKeyEvent->StopPropagation(); aKeyEvent->StopPropagation();
aKeyEvent->StopCrossProcessForwarding(); aKeyEvent->StopCrossProcessForwarding();
aKeyEvent->PreventDefault(); aKeyEvent->PreventDefault();
@ -2406,7 +2411,7 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
// roll up the popup when alt+up/down are pressed within a menulist. // roll up the popup when alt+up/down are pressed within a menulist.
if (aKeyEvent->AltKey() && aTopVisibleMenuItem && if (aKeyEvent->AltKey() && aTopVisibleMenuItem &&
aTopVisibleMenuItem->Frame()->IsMenuList()) { aTopVisibleMenuItem->Frame()->IsMenuList()) {
Rollup(0, false, nullptr, nullptr); Rollup({});
break; break;
} }
[[fallthrough]]; [[fallthrough]];
@ -2433,7 +2438,7 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
// though in this latter case, a menu didn't actually close, the effect // though in this latter case, a menu didn't actually close, the effect
// ends up being the same. Similar for the tab key below. // ends up being the same. Similar for the tab key below.
if (aTopVisibleMenuItem) { if (aTopVisibleMenuItem) {
HidePopup(aTopVisibleMenuItem->Content(), false, false, false, true); HidePopup(aTopVisibleMenuItem->Content(), {HidePopupOption::IsRollup});
} else if (mActiveMenuBar) { } else if (mActiveMenuBar) {
mActiveMenuBar->MenuClosed(); mActiveMenuBar->MenuClosed();
} }
@ -2448,7 +2453,7 @@ bool nsXULPopupManager::HandleKeyboardEventWithKeyCode(
kNameSpaceID_None, nsGkAtoms::activateontab, nsGkAtoms::_true, kNameSpaceID_None, nsGkAtoms::activateontab, nsGkAtoms::_true,
eCaseMatters)) { eCaseMatters)) {
// Close popups or deactivate menubar when Tab or F10 are pressed // Close popups or deactivate menubar when Tab or F10 are pressed
Rollup(0, false, nullptr, nullptr); Rollup({});
break; break;
} else if (mActiveMenuBar) { } else if (mActiveMenuBar) {
mActiveMenuBar->MenuClosed(); mActiveMenuBar->MenuClosed();
@ -2594,7 +2599,7 @@ nsresult nsXULPopupManager::KeyDown(KeyboardEvent* aKeyEvent) {
// modifiers are already down. // modifiers are already down.
nsMenuChainItem* item = GetTopVisibleMenu(); nsMenuChainItem* item = GetTopVisibleMenu();
if (item && !item->Frame()->IsMenuList()) { if (item && !item->Frame()->IsMenuList()) {
Rollup(0, false, nullptr, nullptr); Rollup({});
} else if (mActiveMenuBar) { } else if (mActiveMenuBar) {
mActiveMenuBar->MenuClosed(); mActiveMenuBar->MenuClosed();
} }
@ -2657,7 +2662,7 @@ nsXULPopupHidingEvent::Run() {
nsCOMPtr<nsIContent> nextPopup = mNextPopup; nsCOMPtr<nsIContent> nextPopup = mNextPopup;
nsCOMPtr<nsIContent> lastPopup = mLastPopup; nsCOMPtr<nsIContent> lastPopup = mLastPopup;
pm->FirePopupHidingEvent(popup, nextPopup, lastPopup, presContext, pm->FirePopupHidingEvent(popup, nextPopup, lastPopup, presContext,
mPopupType, mDeselectMenu, mIsRollup); mPopupType, mOptions);
} }
} }
return NS_OK; return NS_OK;
@ -2810,8 +2815,11 @@ nsXULMenuCommandEvent::Run() {
if (mCloseMenuMode != CloseMenuMode_None) { if (mCloseMenuMode != CloseMenuMode_None) {
if (RefPtr popup = menu->GetContainingPopupElement()) { if (RefPtr popup = menu->GetContainingPopupElement()) {
pm->HidePopup(popup, mCloseMenuMode == CloseMenuMode_Auto, true, false, HidePopupOptions options{HidePopupOption::DeselectMenu};
false); if (mCloseMenuMode == CloseMenuMode_Auto) {
options += HidePopupOption::HideChain;
}
pm->HidePopup(popup, options);
} }
} }

Просмотреть файл

@ -161,6 +161,21 @@ enum nsIgnoreKeys {
eIgnoreKeys_Shortcuts, eIgnoreKeys_Shortcuts,
}; };
enum class HidePopupOption : uint8_t {
// If the entire chain of menus should be closed.
HideChain,
// If the parent <menu> of the popup should not be deselected. This will not
// be set when the menu is closed by pressing the Escape key.
DeselectMenu,
// If the first popuphiding event should be sent asynchrously. This should
// be set if HidePopup is called from a frame.
Async,
// If this popup is hiding due to being cancelled.
IsRollup,
};
using HidePopupOptions = mozilla::EnumSet<HidePopupOption>;
#define NS_DIRECTION_IS_INLINE(dir) \ #define NS_DIRECTION_IS_INLINE(dir) \
(dir == eNavigationDirection_Start || dir == eNavigationDirection_End) (dir == eNavigationDirection_Start || dir == eNavigationDirection_End)
#define NS_DIRECTION_IS_BLOCK(dir) \ #define NS_DIRECTION_IS_BLOCK(dir) \
@ -277,14 +292,13 @@ class nsXULPopupHidingEvent : public mozilla::Runnable {
public: public:
nsXULPopupHidingEvent(nsIContent* aPopup, nsIContent* aNextPopup, nsXULPopupHidingEvent(nsIContent* aPopup, nsIContent* aNextPopup,
nsIContent* aLastPopup, nsPopupType aPopupType, nsIContent* aLastPopup, nsPopupType aPopupType,
bool aDeselectMenu, bool aIsCancel) HidePopupOptions aOptions)
: mozilla::Runnable("nsXULPopupHidingEvent"), : mozilla::Runnable("nsXULPopupHidingEvent"),
mPopup(aPopup), mPopup(aPopup),
mNextPopup(aNextPopup), mNextPopup(aNextPopup),
mLastPopup(aLastPopup), mLastPopup(aLastPopup),
mPopupType(aPopupType), mPopupType(aPopupType),
mDeselectMenu(aDeselectMenu), mOptions(aOptions) {
mIsRollup(aIsCancel) {
NS_ASSERTION(aPopup, NS_ASSERTION(aPopup,
"null popup supplied to nsXULPopupHidingEvent constructor"); "null popup supplied to nsXULPopupHidingEvent constructor");
// aNextPopup and aLastPopup may be null // aNextPopup and aLastPopup may be null
@ -297,8 +311,7 @@ class nsXULPopupHidingEvent : public mozilla::Runnable {
nsCOMPtr<nsIContent> mNextPopup; nsCOMPtr<nsIContent> mNextPopup;
nsCOMPtr<nsIContent> mLastPopup; nsCOMPtr<nsIContent> mLastPopup;
nsPopupType mPopupType; nsPopupType mPopupType;
bool mDeselectMenu; HidePopupOptions mOptions;
bool mIsRollup;
}; };
// this class is used for dispatching popuppositioned events asynchronously. // this class is used for dispatching popuppositioned events asynchronously.
@ -370,9 +383,8 @@ class nsXULPopupManager final : public nsIDOMEventListener,
// nsIRollupListener // nsIRollupListener
MOZ_CAN_RUN_SCRIPT_BOUNDARY MOZ_CAN_RUN_SCRIPT_BOUNDARY
bool Rollup(uint32_t aCount, bool aFlush, bool Rollup(const RollupOptions&,
const mozilla::LayoutDeviceIntPoint* aPos, nsIContent** aLastRolledUp = nullptr) override;
nsIContent** aLastRolledUp) override;
bool ShouldRollupOnMouseWheelEvent() override; bool ShouldRollupOnMouseWheelEvent() override;
bool ShouldConsumeOnMouseWheelEvent() override; bool ShouldConsumeOnMouseWheelEvent() override;
bool ShouldRollupOnMouseActivate() override; bool ShouldRollupOnMouseActivate() override;
@ -384,8 +396,7 @@ class nsXULPopupManager final : public nsIDOMEventListener,
enum class RollupKind { Tooltip, Menu }; enum class RollupKind { Tooltip, Menu };
MOZ_CAN_RUN_SCRIPT MOZ_CAN_RUN_SCRIPT
bool RollupInternal(RollupKind, uint32_t aCount, bool aFlush, bool RollupInternal(RollupKind, const RollupOptions&,
const mozilla::LayoutDeviceIntPoint* pos,
nsIContent** aLastRolledUp); nsIContent** aLastRolledUp);
// NativeMenu::Observer // NativeMenu::Observer
@ -502,21 +513,10 @@ class nsXULPopupManager final : public nsIDOMEventListener,
/* /*
* Hide a popup aPopup. If the popup is in a <menu>, then also inform the * Hide a popup aPopup. If the popup is in a <menu>, then also inform the
* menu that the popup is being hidden. * menu that the popup is being hidden.
*
* aHideChain - true if the entire chain of menus should be closed. If false,
* only this popup is closed.
* aDeselectMenu - true if the parent <menu> of the popup should be
* deselected. This will be false when the menu is closed by
* pressing the Escape key.
* aAsynchronous - true if the first popuphiding event should be sent
* asynchrously. This should be true if HidePopup is called
* from a frame.
* aIsCancel - true if this popup is hiding due to being cancelled.
* aLastPopup - optional popup to close last when hiding a chain of menus. * aLastPopup - optional popup to close last when hiding a chain of menus.
* If null, then all popups will be closed. * If null, then all popups will be closed.
*/ */
void HidePopup(nsIContent* aPopup, bool aHideChain, bool aDeselectMenu, void HidePopup(nsIContent* aPopup, HidePopupOptions,
bool aAsynchronous, bool aIsCancel,
nsIContent* aLastPopup = nullptr); nsIContent* aLastPopup = nullptr);
/* /*
@ -747,7 +747,7 @@ class nsXULPopupManager final : public nsIDOMEventListener,
bool aSelectFirstItem); bool aSelectFirstItem);
MOZ_CAN_RUN_SCRIPT void HidePopupCallback( MOZ_CAN_RUN_SCRIPT void HidePopupCallback(
nsIContent* aPopup, nsMenuPopupFrame* aPopupFrame, nsIContent* aNextPopup, nsIContent* aPopup, nsMenuPopupFrame* aPopupFrame, nsIContent* aNextPopup,
nsIContent* aLastPopup, nsPopupType aPopupType, bool aDeselectMenu); nsIContent* aLastPopup, nsPopupType aPopupType, HidePopupOptions);
/** /**
* Trigger frame construction and reflow in the popup, fire a popupshowing * Trigger frame construction and reflow in the popup, fire a popupshowing
@ -779,14 +779,13 @@ class nsXULPopupManager final : public nsIDOMEventListener,
* aLastPopup - the last popup in the chain to hide * aLastPopup - the last popup in the chain to hide
* aPresContext - nsPresContext for the popup's frame * aPresContext - nsPresContext for the popup's frame
* aPopupType - the PopupType of the frame. * aPopupType - the PopupType of the frame.
* aDeselectMenu - true to unhighlight the menu when hiding it * aOptions - the relevant options to hide the popup. Only a subset is looked
* aIsCancel - true if this popup is hiding due to being cancelled. * at.
*/ */
MOZ_CAN_RUN_SCRIPT_BOUNDARY MOZ_CAN_RUN_SCRIPT_BOUNDARY
void FirePopupHidingEvent(nsIContent* aPopup, nsIContent* aNextPopup, void FirePopupHidingEvent(nsIContent* aPopup, nsIContent* aNextPopup,
nsIContent* aLastPopup, nsPresContext* aPresContext, nsIContent* aLastPopup, nsPresContext* aPresContext,
nsPopupType aPopupType, bool aDeselectMenu, nsPopupType aPopupType, HidePopupOptions aOptions);
bool aIsCancel);
/** /**
* Handle keyboard navigation within a menu popup specified by aItem. * Handle keyboard navigation within a menu popup specified by aItem.

Просмотреть файл

@ -474,7 +474,7 @@ void nsXULTooltipListener::LaunchTooltip() {
nsresult nsXULTooltipListener::HideTooltip() { nsresult nsXULTooltipListener::HideTooltip() {
if (nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip)) { if (nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip)) {
if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) { if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
pm->HidePopup(currentTooltip, false, false, false, false); pm->HidePopup(currentTooltip, {});
} }
} }

Просмотреть файл

@ -1037,9 +1037,8 @@ void nsView::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {
bool nsView::RequestWindowClose(nsIWidget* aWidget) { bool nsView::RequestWindowClose(nsIWidget* aWidget) {
if (mFrame && IsPopupWidget(aWidget) && mFrame->IsMenuPopupFrame()) { if (mFrame && IsPopupWidget(aWidget) && mFrame->IsMenuPopupFrame()) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
if (pm) { pm->HidePopup(mFrame->GetContent(), {HidePopupOption::DeselectMenu});
pm->HidePopup(mFrame->GetContent(), false, true, false, false);
return true; return true;
} }
} }

Просмотреть файл

@ -2435,14 +2435,16 @@ NSEvent* gLastDragMouseDownEvent = nil; // [strong]
} }
if (shouldRollup) { if (shouldRollup) {
LayoutDeviceIntPoint devPoint;
nsIRollupListener::RollupOptions rollupOptions{popupsToRollup,
nsIRollupListener::FlushViews::Yes};
if ([theEvent type] == NSEventTypeLeftMouseDown) { if ([theEvent type] == NSEventTypeLeftMouseDown) {
NSPoint point = [NSEvent mouseLocation]; NSPoint point = [NSEvent mouseLocation];
FlipCocoaScreenCoordinate(point); FlipCocoaScreenCoordinate(point);
LayoutDeviceIntPoint devPoint = mGeckoChild->CocoaPointsToDevPixels(point); devPoint = mGeckoChild->CocoaPointsToDevPixels(point);
consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, true, &devPoint, nullptr); rollupOptions.mPoint = &devPoint;
} else {
consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, true, nullptr, nullptr);
} }
consumeEvent = (BOOL)rollupListener->Rollup(rollupOptions);
} }
} }
} }

Просмотреть файл

@ -120,7 +120,7 @@ static void RollUpPopups() {
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget(); nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
if (!rollupWidget) return; if (!rollupWidget) return;
rollupListener->Rollup(0, true, nullptr, nullptr); rollupListener->Rollup({0, nsIRollupListener::FlushViews::Yes});
} }
nsCocoaWindow::nsCocoaWindow() nsCocoaWindow::nsCocoaWindow()

Просмотреть файл

@ -1159,7 +1159,7 @@ void nsMenuX::Dump(uint32_t aIndent) const {
if (rollupListener) { if (rollupListener) {
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget(); nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
if (rollupWidget) { if (rollupWidget) {
rollupListener->Rollup(0, true, nullptr, nullptr); rollupListener->Rollup({0, nsIRollupListener::FlushViews::Yes});
[menu cancelTracking]; [menu cancelTracking];
return; return;
} }

Просмотреть файл

@ -179,7 +179,7 @@ void nsToolkit::MonitorAllProcessMouseEvents() {
return; return;
} }
rollupListener->Rollup(0, false, nullptr, nullptr); rollupListener->Rollup({});
}]; }];
} }

Просмотреть файл

@ -625,7 +625,7 @@ void nsWindow::Destroy() {
if (rollupListener) { if (rollupListener) {
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget(); nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
if (static_cast<nsIWidget*>(this) == rollupWidget) { if (static_cast<nsIWidget*>(this) == rollupWidget) {
rollupListener->Rollup(0, false, nullptr, nullptr); rollupListener->Rollup({});
} }
} }
@ -4017,7 +4017,7 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
// This check avoids unwanted rollup on spurious configure events from // This check avoids unwanted rollup on spurious configure events from
// Cygwin/X (bug 672103). // Cygwin/X (bug 672103).
if (mBounds.x != screenBounds.x || mBounds.y != screenBounds.y) { if (mBounds.x != screenBounds.x || mBounds.y != screenBounds.y) {
CheckForRollup(0, 0, false, true); RollupAllMenus();
} }
} }
@ -4782,7 +4782,7 @@ void nsWindow::OnContainerFocusOutEvent(GdkEventFocus* aEvent) {
}(); }();
if (shouldRollupMenus) { if (shouldRollupMenus) {
CheckForRollup(0, 0, false, true); RollupAllMenus();
} }
if (RefPtr pm = nsXULPopupManager::GetInstance()) { if (RefPtr pm = nsXULPopupManager::GetInstance()) {
@ -7404,19 +7404,24 @@ bool nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
return false; return false;
} }
bool retVal = false;
auto* currentPopup = auto* currentPopup =
(GdkWindow*)rollupWidget->GetNativeData(NS_NATIVE_WINDOW); (GdkWindow*)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
if (aAlwaysRollup || !is_mouse_in_window(currentPopup, aMouseX, aMouseY)) { if (!aAlwaysRollup && is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
bool rollup = true; return false;
if (aIsWheel) {
rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
} }
bool retVal = false;
if (aIsWheel) {
retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
if (!rollupListener->ShouldRollupOnMouseWheelEvent()) {
return retVal;
}
}
LayoutDeviceIntPoint point;
nsIRollupListener::RollupOptions options{0,
nsIRollupListener::FlushViews::Yes};
// if we're dealing with menus, we probably have submenus and // if we're dealing with menus, we probably have submenus and
// we don't want to rollup if the click is in a parent menu of // we don't want to rollup if the click is in a parent menu of
// the current submenu // the current submenu
uint32_t popupsToRollup = UINT32_MAX;
if (!aAlwaysRollup) { if (!aAlwaysRollup) {
AutoTArray<nsIWidget*, 5> widgetChain; AutoTArray<nsIWidget*, 5> widgetChain;
uint32_t sameTypeCount = uint32_t sameTypeCount =
@ -7425,33 +7430,27 @@ bool nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
nsIWidget* widget = widgetChain[i]; nsIWidget* widget = widgetChain[i];
auto* currWindow = (GdkWindow*)widget->GetNativeData(NS_NATIVE_WINDOW); auto* currWindow = (GdkWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) { if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
// don't roll up if the mouse event occurred within a // Don't roll up if the mouse event occurred within a menu of the same
// menu of the same type. If the mouse event occurred // type.
// in a menu higher than that, roll up, but pass the // If the mouse event occurred in a menu higher than that, roll up, but
// number of popups to Rollup so that only those of the // pass the number of popups to Rollup so that only those of the same
// same type close up. // type close up.
if (i < sameTypeCount) { if (i < sameTypeCount) {
rollup = false; return retVal;
} else {
popupsToRollup = sameTypeCount;
} }
options.mCount = sameTypeCount;
break; break;
} }
} // foreach parent menu widget } // foreach parent menu widget
} // if rollup listener knows about menus if (!aIsWheel) {
// if we've determined that we should still rollup, do it.
bool usePoint = !aIsWheel && !aAlwaysRollup;
LayoutDeviceIntPoint point;
if (usePoint) {
point = GdkEventCoordsToDevicePixels(aMouseX, aMouseY); point = GdkEventCoordsToDevicePixels(aMouseX, aMouseY);
options.mPoint = &point;
} }
if (rollup && }
rollupListener->Rollup(popupsToRollup, true,
usePoint ? &point : nullptr, nullptr)) { if (rollupListener->Rollup(options)) {
retVal = true; retVal = true;
} }
}
return retVal; return retVal;
} }

Просмотреть файл

@ -504,7 +504,8 @@ class nsWindow final : public nsBaseWidget {
const mozilla::LayoutDeviceIntPoint& aRefPoint); const mozilla::LayoutDeviceIntPoint& aRefPoint);
bool CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel, bool CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
bool aAlwaysRollup); bool aAlwaysRollup);
void CheckForRollupDuringGrab() { CheckForRollup(0, 0, false, true); } void RollupAllMenus() { CheckForRollup(0, 0, false, true); }
void CheckForRollupDuringGrab() { RollupAllMenus(); }
bool GetDragInfo(mozilla::WidgetMouseEvent* aMouseEvent, GdkWindow** aWindow, bool GetDragInfo(mozilla::WidgetMouseEvent* aMouseEvent, GdkWindow** aWindow,
gint* aButton, gint* aRootX, gint* aRootY); gint* aButton, gint* aRootX, gint* aRootY);

Просмотреть файл

@ -567,7 +567,7 @@ nsBaseDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
if (mDragPopup) { if (mDragPopup) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) { if (pm) {
pm->HidePopup(mDragPopup, false, true, false, false); pm->HidePopup(mDragPopup, {HidePopupOption::DeselectMenu});
} }
} }

Просмотреть файл

@ -16,26 +16,29 @@ class nsIWidget;
class nsIRollupListener { class nsIRollupListener {
public: public:
enum class FlushViews : bool { No, Yes };
struct RollupOptions {
// aCount is the number of popups in a chain to close. If this is
// zero, then all popups are closed.
uint32_t mCount = 0;
// If this is true, then views should be flushed after the rollup.
FlushViews mFlush = FlushViews::No;
// This is the mouse pointer position where the event that triggered the
// rollup occurred, which may be nullptr.
const mozilla::LayoutDeviceIntPoint* mPoint = nullptr;
};
/** /**
* Notifies the object to rollup, optionally returning the node that * Notifies the object to rollup, optionally returning the node that
* was just rolled up. * was just rolled up in aLastRolledUp, if non-null.
* *
* If aFlush is true, then views should be flushed after the rollup. * aLastRolledUp is not addrefed.
*
* aPoint is the mouse pointer position where the event that triggered the
* rollup occurred, which may be nullptr.
*
* aCount is the number of popups in a chain to close. If this is
* UINT32_MAX, then all popups are closed.
* If aLastRolledUp is non-null, it will be set to the last rolled up popup,
* if this is supported. aLastRolledUp is not addrefed.
* *
* Returns true if the event that the caller is processing should be consumed. * Returns true if the event that the caller is processing should be consumed.
*/ */
MOZ_CAN_RUN_SCRIPT_BOUNDARY MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool Rollup(uint32_t aCount, bool aFlush, virtual bool Rollup(const RollupOptions&,
const mozilla::LayoutDeviceIntPoint* aPoint, nsIContent** aLastRolledUp = nullptr) = 0;
nsIContent** aLastRolledUp) = 0;
/** /**
* Asks the RollupListener if it should rollup on mouse wheel events * Asks the RollupListener if it should rollup on mouse wheel events

Просмотреть файл

@ -7414,7 +7414,7 @@ void nsWindow::OnDestroy() {
rollupWidget = rollupListener->GetRollupWidget(); rollupWidget = rollupListener->GetRollupWidget();
} }
if (this == rollupWidget) { if (this == rollupWidget) {
if (rollupListener) rollupListener->Rollup(0, false, nullptr, nullptr); rollupListener->Rollup({});
CaptureRollupEvents(false); CaptureRollupEvents(false);
} }
@ -8408,6 +8408,11 @@ bool nsWindow::DealWithPopups(HWND aWnd, UINT aMessage, WPARAM aWParam,
// Only need to deal with the last rollup for left mouse down events. // Only need to deal with the last rollup for left mouse down events.
NS_ASSERTION(!nsAutoRollup::GetLastRollup(), "last rollup is null"); NS_ASSERTION(!nsAutoRollup::GetLastRollup(), "last rollup is null");
nsIRollupListener::RollupOptions rollupOptions{
popupsToRollup,
nsIRollupListener::FlushViews::Yes,
};
if (nativeMessage == WM_TOUCH || nativeMessage == WM_LBUTTONDOWN || if (nativeMessage == WM_TOUCH || nativeMessage == WM_LBUTTONDOWN ||
nativeMessage == WM_POINTERDOWN) { nativeMessage == WM_POINTERDOWN) {
LayoutDeviceIntPoint pos; LayoutDeviceIntPoint pos;
@ -8425,13 +8430,12 @@ bool nsWindow::DealWithPopups(HWND aWnd, UINT aMessage, WPARAM aWParam,
pos = LayoutDeviceIntPoint(pt.x, pt.y); pos = LayoutDeviceIntPoint(pt.x, pt.y);
} }
nsIContent* lastRollup; rollupOptions.mPoint = &pos;
consumeRollupEvent = nsIContent* lastRollup = nullptr;
rollupListener->Rollup(popupsToRollup, true, &pos, &lastRollup); consumeRollupEvent = rollupListener->Rollup(rollupOptions, &lastRollup);
nsAutoRollup::SetLastRollup(lastRollup); nsAutoRollup::SetLastRollup(lastRollup);
} else { } else {
consumeRollupEvent = consumeRollupEvent = rollupListener->Rollup(rollupOptions);
rollupListener->Rollup(popupsToRollup, true, nullptr, nullptr);
} }
// Tell hook to stop processing messages // Tell hook to stop processing messages