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);
|
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) {
|
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();
|
auto parent = aItem->Detach();
|
||||||
if (auto* child = aItem->GetChild()) {
|
if (auto* child = aItem->GetChild()) {
|
||||||
MOZ_ASSERT(aItem != mPopups,
|
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() {
|
void nsMenuChainItem::UpdateFollowAnchor() {
|
||||||
mFollowAnchor = mFrame->ShouldFollowAnchor(mCurrentRect);
|
mFollowAnchor = mFrame->ShouldFollowAnchor(mCurrentRect);
|
||||||
}
|
}
|
||||||
|
|
@ -1140,17 +1188,7 @@ void nsXULPopupManager::ShowPopupCallback(Element* aPopup,
|
||||||
|
|
||||||
item->UpdateFollowAnchor();
|
item->UpdateFollowAnchor();
|
||||||
|
|
||||||
// popups normally hide when an outside click occurs. Panels may use
|
AddMenuChainItem(std::move(item));
|
||||||
// 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);
|
|
||||||
NS_ENSURE_TRUE_VOID(weakFrame.IsAlive());
|
NS_ENSURE_TRUE_VOID(weakFrame.IsAlive());
|
||||||
|
|
||||||
RefPtr popup = &aPopupFrame->PopupElement();
|
RefPtr popup = &aPopupFrame->PopupElement();
|
||||||
|
|
@ -1166,12 +1204,10 @@ void nsXULPopupManager::ShowPopupCallback(Element* aPopup,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMenuChainItem* nsXULPopupManager::FindPopup(Element* aPopup) const {
|
nsMenuChainItem* nsXULPopupManager::FindPopup(Element* aPopup) const {
|
||||||
for (nsMenuChainItem* item = mPopups.get(); item; item = item->GetParent()) {
|
auto matcher = [&](nsMenuChainItem* aItem) -> bool {
|
||||||
if (item->Frame()->GetContent() == aPopup) {
|
return aItem->Frame()->GetContent() == aPopup;
|
||||||
return item;
|
};
|
||||||
}
|
return FirstMatchingPopup(matcher);
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsXULPopupManager::HidePopup(Element* aPopup, HidePopupOptions aOptions,
|
void nsXULPopupManager::HidePopup(Element* aPopup, HidePopupOptions aOptions,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/FunctionRef.h"
|
||||||
#include "mozilla/widget/InitData.h"
|
#include "mozilla/widget/InitData.h"
|
||||||
#include "mozilla/widget/NativeMenu.h"
|
#include "mozilla/widget/NativeMenu.h"
|
||||||
|
|
||||||
|
|
@ -550,6 +551,13 @@ class nsXULPopupManager final : public nsIDOMEventListener,
|
||||||
*/
|
*/
|
||||||
void UpdatePopupPositions(nsRefreshDriver* aRefreshDriver);
|
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.
|
* Enable or disable anchor following on the popup if needed.
|
||||||
*/
|
*/
|
||||||
|
|
@ -733,6 +741,9 @@ class nsXULPopupManager final : public nsIDOMEventListener,
|
||||||
return GetRollupItem(RollupKind::Menu);
|
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.
|
// Removes the chain item from the chain and deletes it.
|
||||||
void RemoveMenuChainItem(nsMenuChainItem*);
|
void RemoveMenuChainItem(nsMenuChainItem*);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8844,6 +8844,11 @@
|
||||||
value: 32
|
value: 32
|
||||||
mirror: always
|
mirror: always
|
||||||
|
|
||||||
|
- name: layout.cursor.disable-for-popups
|
||||||
|
type: bool
|
||||||
|
value: true
|
||||||
|
mirror: always
|
||||||
|
|
||||||
- name: layout.display-list.build-twice
|
- name: layout.display-list.build-twice
|
||||||
type: RelaxedAtomicBool
|
type: RelaxedAtomicBool
|
||||||
value: false
|
value: false
|
||||||
|
|
|
||||||
|
|
@ -625,9 +625,12 @@ void nsChildView::SetCursor(const Cursor& aCursor) {
|
||||||
|
|
||||||
nsBaseWidget::SetCursor(aCursor);
|
nsBaseWidget::SetCursor(aCursor);
|
||||||
|
|
||||||
if (NS_SUCCEEDED([[nsCursorManager sharedInstance]
|
bool forceUpdate = mUpdateCursor;
|
||||||
setCustomCursor:aCursor
|
mUpdateCursor = false;
|
||||||
widgetScaleFactor:BackingScaleFactor()])) {
|
if (mCustomCursorAllowed && NS_SUCCEEDED([[nsCursorManager sharedInstance]
|
||||||
|
setCustomCursor:aCursor
|
||||||
|
widgetScaleFactor:BackingScaleFactor()
|
||||||
|
forceUpdate:forceUpdate])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@
|
||||||
// As above, but returns an error if the cursor isn't custom or we couldn't set
|
// As above, but returns an error if the cursor isn't custom or we couldn't set
|
||||||
// it for some reason.
|
// it for some reason.
|
||||||
- (nsresult)setCustomCursor:(const nsIWidget::Cursor&)aCursor
|
- (nsresult)setCustomCursor:(const nsIWidget::Cursor&)aCursor
|
||||||
widgetScaleFactor:(CGFloat)aWidgetScaleFactor;
|
widgetScaleFactor:(CGFloat)aWidgetScaleFactor
|
||||||
|
forceUpdate:(bool)aForceUpdate;
|
||||||
|
|
||||||
/*! @method sharedInstance
|
/*! @method sharedInstance
|
||||||
@abstract Get the Singleton instance of the cursor manager.
|
@abstract Get the Singleton instance of the cursor manager.
|
||||||
|
|
|
||||||
|
|
@ -276,13 +276,14 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nsresult)setCustomCursor:(const nsIWidget::Cursor&)aCursor
|
- (nsresult)setCustomCursor:(const nsIWidget::Cursor&)aCursor
|
||||||
widgetScaleFactor:(CGFloat)scaleFactor {
|
widgetScaleFactor:(CGFloat)scaleFactor
|
||||||
|
forceUpdate:(bool)aForceUpdate {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
// As the user moves the mouse, this gets called repeatedly with the same
|
// As the user moves the mouse, this gets called repeatedly with the same
|
||||||
// aCursorImage
|
// aCursorImage
|
||||||
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor &&
|
if (!aForceUpdate && sCurrentCursor == aCursor &&
|
||||||
mCurrentMacCursor) {
|
sCurrentCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
|
||||||
// Native dragging can unset our cursor apparently (see bug 1739352).
|
// Native dragging can unset our cursor apparently (see bug 1739352).
|
||||||
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
|
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
|
||||||
[mCurrentMacCursor set];
|
[mCurrentMacCursor set];
|
||||||
|
|
|
||||||
|
|
@ -3328,7 +3328,10 @@ void nsWindow::SetCursor(const Cursor& aCursor) {
|
||||||
mCursor = aCursor;
|
mCursor = aCursor;
|
||||||
|
|
||||||
// Try to set the cursor image first, and fall back to the numeric cursor.
|
// 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
|
// 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
|
// 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::SetCursor(const Cursor& aCursor) { mCursor = aCursor; }
|
||||||
|
|
||||||
|
void nsBaseWidget::SetCustomCursorAllowed(bool aIsAllowed) {
|
||||||
|
if (aIsAllowed != mCustomCursorAllowed) {
|
||||||
|
mCustomCursorAllowed = aIsAllowed;
|
||||||
|
mUpdateCursor = true;
|
||||||
|
SetCursor(mCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Window transparency methods
|
// Window transparency methods
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
|
||||||
bool IsFullyOccluded() const override { return mIsFullyOccluded; }
|
bool IsFullyOccluded() const override { return mIsFullyOccluded; }
|
||||||
|
|
||||||
void SetCursor(const Cursor&) override;
|
void SetCursor(const Cursor&) override;
|
||||||
|
void SetCustomCursorAllowed(bool) override;
|
||||||
void ClearCachedCursor() final {
|
void ClearCachedCursor() final {
|
||||||
mCursor = {};
|
mCursor = {};
|
||||||
mUpdateCursor = true;
|
mUpdateCursor = true;
|
||||||
|
|
@ -694,6 +695,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
|
||||||
RefPtr<mozilla::SwipeTracker> mSwipeTracker;
|
RefPtr<mozilla::SwipeTracker> mSwipeTracker;
|
||||||
mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
|
mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
|
||||||
Cursor mCursor;
|
Cursor mCursor;
|
||||||
|
bool mCustomCursorAllowed = true;
|
||||||
BorderStyle mBorderStyle;
|
BorderStyle mBorderStyle;
|
||||||
LayoutDeviceIntRect mBounds;
|
LayoutDeviceIntRect mBounds;
|
||||||
bool mIsTiled;
|
bool mIsTiled;
|
||||||
|
|
|
||||||
|
|
@ -1014,6 +1014,8 @@ class nsIWidget : public nsISupports {
|
||||||
*/
|
*/
|
||||||
virtual void SetCursor(const Cursor&) = 0;
|
virtual void SetCursor(const Cursor&) = 0;
|
||||||
|
|
||||||
|
virtual void SetCustomCursorAllowed(bool) = 0;
|
||||||
|
|
||||||
static nsIntSize CustomCursorSize(const Cursor&);
|
static nsIntSize CustomCursorSize(const Cursor&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -3031,7 +3031,10 @@ void nsWindow::SetCursor(const Cursor& aCursor) {
|
||||||
sCurrentHCursorIsCustom = false;
|
sCurrentHCursorIsCustom = false;
|
||||||
sCurrentCursor = aCursor;
|
sCurrentCursor = aCursor;
|
||||||
|
|
||||||
HCURSOR cursor = CursorForImage(aCursor, GetDefaultScale());
|
HCURSOR cursor = nullptr;
|
||||||
|
if (mCustomCursorAllowed) {
|
||||||
|
cursor = CursorForImage(aCursor, GetDefaultScale());
|
||||||
|
}
|
||||||
bool custom = false;
|
bool custom = false;
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
custom = true;
|
custom = true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue