forked from mirrors/gecko-dev
Bug 1833814 - change nsIWidget's cursor logic, r=emilio,win-reviewers,mhowell
Differential Revision: https://phabricator.services.mozilla.com/D195549
This commit is contained in:
parent
e4df13ce23
commit
6674caa946
11 changed files with 101 additions and 26 deletions
|
|
@ -209,7 +209,44 @@ UniquePtr<nsMenuChainItem> nsMenuChainItem::Detach() {
|
|||
return std::move(mParent);
|
||||
}
|
||||
|
||||
void nsXULPopupManager::AddMenuChainItem(UniquePtr<nsMenuChainItem> aItem) {
|
||||
PopupType popupType = aItem->Frame()->GetPopupType();
|
||||
if (StaticPrefs::layout_cursor_disable_for_popups() &&
|
||||
popupType != PopupType::Tooltip) {
|
||||
nsPresContext* rootPresContext =
|
||||
aItem->Frame()->PresContext()->GetRootPresContext();
|
||||
if (nsCOMPtr<nsIWidget> rootWidget = rootPresContext->GetRootWidget()) {
|
||||
rootWidget->SetCustomCursorAllowed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// popups normally hide when an outside click occurs. Panels may use
|
||||
// the noautohide attribute to disable this behaviour. It is expected
|
||||
// that the application will hide these popups manually. The tooltip
|
||||
// listener will handle closing the tooltip also.
|
||||
nsIContent* oldmenu = nullptr;
|
||||
if (mPopups) {
|
||||
oldmenu = mPopups->Element();
|
||||
}
|
||||
aItem->SetParent(std::move(mPopups));
|
||||
mPopups = std::move(aItem);
|
||||
SetCaptureState(oldmenu);
|
||||
}
|
||||
|
||||
void nsXULPopupManager::RemoveMenuChainItem(nsMenuChainItem* aItem) {
|
||||
nsPresContext* presContext =
|
||||
aItem->Frame()->PresContext()->GetRootPresContext();
|
||||
auto matcher = [&](nsMenuChainItem* aChainItem) -> bool {
|
||||
return aChainItem != aItem &&
|
||||
presContext ==
|
||||
aChainItem->Frame()->PresContext()->GetRootPresContext();
|
||||
};
|
||||
nsCOMPtr<nsIWidget> rootWidget =
|
||||
presContext->GetRootPresContext()->GetRootWidget();
|
||||
if (!FirstMatchingPopup(matcher) && rootWidget) {
|
||||
rootWidget->SetCustomCursorAllowed(true);
|
||||
}
|
||||
|
||||
auto parent = aItem->Detach();
|
||||
if (auto* child = aItem->GetChild()) {
|
||||
MOZ_ASSERT(aItem != mPopups,
|
||||
|
|
@ -225,6 +262,17 @@ void nsXULPopupManager::RemoveMenuChainItem(nsMenuChainItem* aItem) {
|
|||
}
|
||||
}
|
||||
|
||||
nsMenuChainItem* nsXULPopupManager::FirstMatchingPopup(
|
||||
mozilla::FunctionRef<bool(nsMenuChainItem*)> aMatcher) const {
|
||||
for (nsMenuChainItem* popup = mPopups.get(); popup;
|
||||
popup = popup->GetParent()) {
|
||||
if (aMatcher(popup)) {
|
||||
return popup;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void nsMenuChainItem::UpdateFollowAnchor() {
|
||||
mFollowAnchor = mFrame->ShouldFollowAnchor(mCurrentRect);
|
||||
}
|
||||
|
|
@ -1140,17 +1188,7 @@ void nsXULPopupManager::ShowPopupCallback(Element* aPopup,
|
|||
|
||||
item->UpdateFollowAnchor();
|
||||
|
||||
// popups normally hide when an outside click occurs. Panels may use
|
||||
// the noautohide attribute to disable this behaviour. It is expected
|
||||
// that the application will hide these popups manually. The tooltip
|
||||
// listener will handle closing the tooltip also.
|
||||
nsIContent* oldmenu = nullptr;
|
||||
if (mPopups) {
|
||||
oldmenu = mPopups->Element();
|
||||
}
|
||||
item->SetParent(std::move(mPopups));
|
||||
mPopups = std::move(item);
|
||||
SetCaptureState(oldmenu);
|
||||
AddMenuChainItem(std::move(item));
|
||||
NS_ENSURE_TRUE_VOID(weakFrame.IsAlive());
|
||||
|
||||
RefPtr popup = &aPopupFrame->PopupElement();
|
||||
|
|
@ -1166,12 +1204,10 @@ void nsXULPopupManager::ShowPopupCallback(Element* aPopup,
|
|||
}
|
||||
|
||||
nsMenuChainItem* nsXULPopupManager::FindPopup(Element* aPopup) const {
|
||||
for (nsMenuChainItem* item = mPopups.get(); item; item = item->GetParent()) {
|
||||
if (item->Frame()->GetContent() == aPopup) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
auto matcher = [&](nsMenuChainItem* aItem) -> bool {
|
||||
return aItem->Frame()->GetContent() == aPopup;
|
||||
};
|
||||
return FirstMatchingPopup(matcher);
|
||||
}
|
||||
|
||||
void nsXULPopupManager::HidePopup(Element* aPopup, HidePopupOptions aOptions,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "nsIObserver.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FunctionRef.h"
|
||||
#include "mozilla/widget/InitData.h"
|
||||
#include "mozilla/widget/NativeMenu.h"
|
||||
|
||||
|
|
@ -550,6 +551,13 @@ class nsXULPopupManager final : public nsIDOMEventListener,
|
|||
*/
|
||||
void UpdatePopupPositions(nsRefreshDriver* aRefreshDriver);
|
||||
|
||||
/**
|
||||
* Get the first nsMenuChainItem that is matched by the matching callback
|
||||
* function provided.
|
||||
*/
|
||||
nsMenuChainItem* FirstMatchingPopup(
|
||||
mozilla::FunctionRef<bool(nsMenuChainItem*)> aMatcher) const;
|
||||
|
||||
/**
|
||||
* Enable or disable anchor following on the popup if needed.
|
||||
*/
|
||||
|
|
@ -733,6 +741,9 @@ class nsXULPopupManager final : public nsIDOMEventListener,
|
|||
return GetRollupItem(RollupKind::Menu);
|
||||
}
|
||||
|
||||
// Add the chain item to the chain and update mPopups to point to it.
|
||||
void AddMenuChainItem(mozilla::UniquePtr<nsMenuChainItem>);
|
||||
|
||||
// Removes the chain item from the chain and deletes it.
|
||||
void RemoveMenuChainItem(nsMenuChainItem*);
|
||||
|
||||
|
|
|
|||
|
|
@ -8844,6 +8844,11 @@
|
|||
value: 32
|
||||
mirror: always
|
||||
|
||||
- name: layout.cursor.disable-for-popups
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: layout.display-list.build-twice
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
|
|
|
|||
|
|
@ -625,9 +625,12 @@ void nsChildView::SetCursor(const Cursor& aCursor) {
|
|||
|
||||
nsBaseWidget::SetCursor(aCursor);
|
||||
|
||||
if (NS_SUCCEEDED([[nsCursorManager sharedInstance]
|
||||
setCustomCursor:aCursor
|
||||
widgetScaleFactor:BackingScaleFactor()])) {
|
||||
bool forceUpdate = mUpdateCursor;
|
||||
mUpdateCursor = false;
|
||||
if (mCustomCursorAllowed && NS_SUCCEEDED([[nsCursorManager sharedInstance]
|
||||
setCustomCursor:aCursor
|
||||
widgetScaleFactor:BackingScaleFactor()
|
||||
forceUpdate:forceUpdate])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@
|
|||
// As above, but returns an error if the cursor isn't custom or we couldn't set
|
||||
// it for some reason.
|
||||
- (nsresult)setCustomCursor:(const nsIWidget::Cursor&)aCursor
|
||||
widgetScaleFactor:(CGFloat)aWidgetScaleFactor;
|
||||
widgetScaleFactor:(CGFloat)aWidgetScaleFactor
|
||||
forceUpdate:(bool)aForceUpdate;
|
||||
|
||||
/*! @method sharedInstance
|
||||
@abstract Get the Singleton instance of the cursor manager.
|
||||
|
|
|
|||
|
|
@ -276,13 +276,14 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
}
|
||||
|
||||
- (nsresult)setCustomCursor:(const nsIWidget::Cursor&)aCursor
|
||||
widgetScaleFactor:(CGFloat)scaleFactor {
|
||||
widgetScaleFactor:(CGFloat)scaleFactor
|
||||
forceUpdate:(bool)aForceUpdate {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
// As the user moves the mouse, this gets called repeatedly with the same
|
||||
// aCursorImage
|
||||
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor &&
|
||||
mCurrentMacCursor) {
|
||||
if (!aForceUpdate && sCurrentCursor == aCursor &&
|
||||
sCurrentCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
|
||||
// Native dragging can unset our cursor apparently (see bug 1739352).
|
||||
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
|
||||
[mCurrentMacCursor set];
|
||||
|
|
|
|||
|
|
@ -3328,7 +3328,10 @@ void nsWindow::SetCursor(const Cursor& aCursor) {
|
|||
mCursor = aCursor;
|
||||
|
||||
// Try to set the cursor image first, and fall back to the numeric cursor.
|
||||
GdkCursor* imageCursor = GetCursorForImage(aCursor, GdkCeiledScaleFactor());
|
||||
GdkCursor* imageCursor = nullptr;
|
||||
if (mCustomCursorAllowed) {
|
||||
imageCursor = GetCursorForImage(aCursor, GdkCeiledScaleFactor());
|
||||
}
|
||||
|
||||
// When using a custom cursor, clear the cursor first using eCursor_none, in
|
||||
// order to work around https://gitlab.gnome.org/GNOME/gtk/-/issues/6242
|
||||
|
|
|
|||
|
|
@ -701,6 +701,14 @@ void nsBaseWidget::MoveToWorkspace(const nsAString& workspaceID) {
|
|||
|
||||
void nsBaseWidget::SetCursor(const Cursor& aCursor) { mCursor = aCursor; }
|
||||
|
||||
void nsBaseWidget::SetCustomCursorAllowed(bool aIsAllowed) {
|
||||
if (aIsAllowed != mCustomCursorAllowed) {
|
||||
mCustomCursorAllowed = aIsAllowed;
|
||||
mUpdateCursor = true;
|
||||
SetCursor(mCursor);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Window transparency methods
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
|
|||
bool IsFullyOccluded() const override { return mIsFullyOccluded; }
|
||||
|
||||
void SetCursor(const Cursor&) override;
|
||||
void SetCustomCursorAllowed(bool) override;
|
||||
void ClearCachedCursor() final {
|
||||
mCursor = {};
|
||||
mUpdateCursor = true;
|
||||
|
|
@ -694,6 +695,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
|
|||
RefPtr<mozilla::SwipeTracker> mSwipeTracker;
|
||||
mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
|
||||
Cursor mCursor;
|
||||
bool mCustomCursorAllowed = true;
|
||||
BorderStyle mBorderStyle;
|
||||
LayoutDeviceIntRect mBounds;
|
||||
bool mIsTiled;
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,8 @@ class nsIWidget : public nsISupports {
|
|||
*/
|
||||
virtual void SetCursor(const Cursor&) = 0;
|
||||
|
||||
virtual void SetCustomCursorAllowed(bool) = 0;
|
||||
|
||||
static nsIntSize CustomCursorSize(const Cursor&);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3031,7 +3031,10 @@ void nsWindow::SetCursor(const Cursor& aCursor) {
|
|||
sCurrentHCursorIsCustom = false;
|
||||
sCurrentCursor = aCursor;
|
||||
|
||||
HCURSOR cursor = CursorForImage(aCursor, GetDefaultScale());
|
||||
HCURSOR cursor = nullptr;
|
||||
if (mCustomCursorAllowed) {
|
||||
cursor = CursorForImage(aCursor, GetDefaultScale());
|
||||
}
|
||||
bool custom = false;
|
||||
if (cursor) {
|
||||
custom = true;
|
||||
|
|
|
|||
Loading…
Reference in a new issue