Files
Sky Ning dc0bff8eaf Bug 2031413 - Update sLastPointerId at eMouseEnterIntoWidget so the synthesized eMouseMove can update the cursor. r=masayuki,dom-core
Per Masayuki's suggestion on D302222 (taking my mozregression bisect
result as the entry point): the underlying issue is that the existing
self-heal path through PresShell::RecordPointerLocation ->
SynthesizeMouseMove -> EventStateManager::UpdateCursor cannot complete
when sLastPointerId has been cleared, because eMouseEnterIntoWidget
itself does not restore it.

Today PointerEventHandler::UpdatePointerActiveState deliberately skips
UpdateLastPointerId for eMouseEnterIntoWidget. PresShell still
schedules a synthesized eMouseMove for it, but that synthesized event
fails the IsLastPointerId check bug 1980636 added in
EventStateManager::UpdateCursor and returns before updating the
on-screen cursor.

This is observable on macOS native fullscreen: AppKit tears down the
old content view's NSTrackingArea and installs one on the new
fullscreen view, firing a real mouseExited / mouseEntered pair on the
old view even though the cursor never moves. The mouseExited dispatches
eMouseExitFromWidget, which clears sLastPointerId. The matching
mouseEntered then dispatches eMouseEnterIntoWidget and schedules the
self-heal synthesized eMouseMove — which currently can't complete the
cursor update because sLastPointerId has not been restored. As a
result, e.g. YouTube/Bilibili's autohide `cursor: none` does not take
effect after the user enters fullscreen until they move the mouse.

Restore the UpdateLastPointerId call in the eMouseEnterIntoWidget arm
of UpdatePointerActiveState (and drop the now-incorrect comment), and
remove the corresponding MOZ_ASSERT in UpdateLastPointerId itself.

Also drop MOZDynamicCursor::reassertCurrentCursor (the previous fix in
this bug, from D299187) and its call site in
nsCocoaWindow::CocoaWindowDidEnterFullscreen. With this patch the
self-heal path through PresShell -> EventStateManager -> SetCursor
restores the correct cursor after the transition, so there is no
cached state left to reassert.

mozregression bisected the user-visible symptom to bug 1980636 (last
good 143.0a1, first bad 144.0a1).

Differential Revision: https://phabricator.services.mozilla.com/D302222
2026-05-26 13:28:48 +00:00

38 lines
1.3 KiB
Objective-C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZDynamicCursor_h_
#define MOZDynamicCursor_h_
#import <Cocoa/Cocoa.h>
#include "nsIWidget.h"
// MOZDynamicCursor.sharedInstance is a singleton NSCursor object whose
// underlying cursor can be changed at runtime.
// It can be used in an NSView cursorRect so that the system will call
// -[NSCursor set] on it at the right moments, for example when the
// mouse moves into a window or when the cursor needs to be set after
// a drag operation or when a context menu closes.
@interface MOZDynamicCursor : NSCursor {
@private
NSMutableDictionary* mCursors;
NSCursor* mCurrentCursor;
nsCursor mCurrentCursorType;
}
// Sets non-custom cursors and can be used as a fallback if setting
// a custom cursor did not succeed.
- (void)setNonCustomCursor:(const nsIWidget::Cursor&)aCursor;
// 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
forceUpdate:(bool)aForceUpdate;
+ (MOZDynamicCursor*)sharedInstance;
@end
#endif // MOZDynamicCursor_h_