Bug 1437941: Don't ignore mousemove after fullscreen transition
MozReview-Commit-ID: Hr9dcKVeYEC
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -4166,16 +4166,17 @@ FullscreenTransitionTask::Run()
} else if (stage == eAfterToggle) {
Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
mFullscreenChangeStartTime);
mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
mDuration.mFadeOut, mTransitionData,
this);
} else if (stage == eEnd) {
PROFILER_ADD_MARKER("Fullscreen transition end");
+ mWidget->CleanupFullscreenTransition();
}
return NS_OK;
}
NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer, nsIObserver)
NS_IMETHODIMP
FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -187,16 +187,17 @@ public:
virtual void SetShowsFullScreenButton(bool aShow) override {}
virtual void SetWindowAnimationType(WindowAnimationType aType) override {}
virtual void HideWindowChrome(bool aShouldHide) override {}
virtual bool PrepareForFullscreenTransition(nsISupports** aData) override { return false; }
virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
uint16_t aDuration,
nsISupports* aData,
nsIRunnable* aCallback) override;
+ virtual void CleanupFullscreenTransition() override {};
virtual already_AddRefed<nsIScreen> GetWidgetScreen() override;
virtual nsresult MakeFullScreen(bool aFullScreen,
nsIScreen* aScreen = nullptr) override;
void InfallibleMakeFullScreen(bool aFullScreen,
nsIScreen* aScreen = nullptr);
virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1208,16 +1208,21 @@ class nsIWidget : public nsISupports
* finishes.
*/
virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
uint16_t aDuration,
nsISupports* aData,
nsIRunnable* aCallback) = 0;
/**
+ * Perform any actions needed after the fullscreen transition has ended.
+ */
+ virtual void CleanupFullscreenTransition() = 0;
+
+ /**
* Return the screen the widget is in, or null if we don't know.
*/
virtual already_AddRefed<nsIScreen> GetWidgetScreen() = 0;
/**
* Put the toplevel window into or out of fullscreen mode.
* If aTargetScreen is given, attempt to go fullscreen on that screen,
* if possible. (If not, it behaves as if aTargetScreen is null.)
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -266,19 +266,16 @@ POINT nsWindow::sLastMouseMove
LONG nsWindow::sLastMouseDownTime = 0L;
LONG nsWindow::sLastClickCount = 0L;
BYTE nsWindow::sLastMouseButton = 0;
bool nsWindow::sHaveInitializedPrefs = false;
TriStateBool nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor = TRI_UNKNOWN;
-WPARAM nsWindow::sMouseExitwParam = 0;
-LPARAM nsWindow::sMouseExitlParamScreen = 0;
-
static SystemTimeConverter<DWORD>&
TimeConverter() {
static SystemTimeConverter<DWORD> timeConverterSingleton;
return timeConverterSingleton;
}
namespace mozilla {
@@ -1960,18 +1957,16 @@ nsWindow::Resize(double aX, double aY, d
ChangedDPI();
}
if (mTransitionWnd) {
// If we have a fullscreen transition window, we need to make
// it topmost again, otherwise the taskbar may be raised by
// the system unexpectedly when we leave fullscreen state.
::SetWindowPos(mTransitionWnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
- // Every transition window is only used once.
- mTransitionWnd = nullptr;
}
SetThemeRegion();
}
if (aRepaint)
Invalidate();
NotifyRollupGeometryChange();
@@ -3436,16 +3431,17 @@ nsWindow::PrepareForFullscreenTransition
::WaitForSingleObject(initData.mSemaphore, INFINITE);
}
}
if (!initData.mWnd) {
return false;
}
mTransitionWnd = initData.mWnd;
+
auto data = new FullscreenTransitionData(initData.mWnd);
*aData = data;
NS_ADDREF(data);
return true;
}
/* virtual */ void
nsWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage,
@@ -3455,16 +3451,25 @@ nsWindow::PerformFullscreenTransition(Fu
auto data = static_cast<FullscreenTransitionData*>(aData);
nsCOMPtr<nsIRunnable> callback = aCallback;
UINT msg = aStage == eBeforeFullscreenToggle ?
WM_FULLSCREEN_TRANSITION_BEFORE : WM_FULLSCREEN_TRANSITION_AFTER;
WPARAM wparam = (WPARAM)callback.forget().take();
::PostMessage(data->mWnd, msg, wparam, (LPARAM)aDuration);
}
+/* virtual */ void
+nsWindow::CleanupFullscreenTransition()
+{
+ MOZ_ASSERT(NS_IsMainThread(), "CleanupFullscreenTransition "
+ "should only run on the main thread");
+
+ mTransitionWnd = nullptr;
+}
+
nsresult
nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
{
// taskbarInfo will be nullptr pre Windows 7 until Bug 680227 is resolved.
nsCOMPtr<nsIWinTaskbar> taskbarInfo =
do_GetService(NS_TASKBAR_CONTRACTID);
mFullscreenMode = aFullScreen;
@@ -3504,27 +3509,16 @@ nsWindow::MakeFullScreen(bool aFullScree
taskbarInfo->PrepareFullScreenHWND(mWnd, FALSE);
}
if (mWidgetListener) {
mWidgetListener->SizeModeChanged(mSizeMode);
mWidgetListener->FullscreenChanged(aFullScreen);
}
- // Send a eMouseEnterIntoWidget event since Windows has already sent
- // a WM_MOUSELEAVE that caused us to send a eMouseExitFromWidget event.
- if (aFullScreen && !sCurrentWindow) {
- sCurrentWindow = this;
- LPARAM pos = sCurrentWindow->lParamToClient(sMouseExitlParamScreen);
- sCurrentWindow->DispatchMouseEvent(eMouseEnterIntoWidget,
- sMouseExitwParam, pos, false,
- WidgetMouseEvent::eLeftButton,
- MOUSE_INPUT_SOURCE());
- }
-
return NS_OK;
}
/**************************************************************
*
* SECTION: Native data storage
*
* nsIWidget::GetNativeData
@@ -4651,18 +4645,16 @@ nsWindow::DispatchMouseEvent(EventMessag
sCurrentWindow->DispatchMouseEvent(eMouseEnterIntoWidget,
wParam, pos, false,
WidgetMouseEvent::eLeftButton,
aInputSource, aPointerInfo);
}
}
}
} else if (aEventMessage == eMouseExitFromWidget) {
- sMouseExitwParam = wParam;
- sMouseExitlParamScreen = lParamToScreen(lParam);
if (sCurrentWindow == this) {
sCurrentWindow = nullptr;
}
}
result = ConvertStatus(DispatchInputEvent(&event));
// Release the widget with NS_IF_RELEASE() just in case
@@ -4705,23 +4697,28 @@ void nsWindow::DispatchFocusToTopLevelWi
if (!win->BlurEventsSuppressed()) {
win->mWidgetListener->WindowDeactivated();
}
}
}
}
}
-bool nsWindow::IsTopLevelMouseExit(HWND aWnd)
+HWND nsWindow::WindowAtMouse()
{
DWORD pos = ::GetMessagePos();
POINT mp;
mp.x = GET_X_LPARAM(pos);
mp.y = GET_Y_LPARAM(pos);
- HWND mouseWnd = ::WindowFromPoint(mp);
+ return ::WindowFromPoint(mp);
+}
+
+bool nsWindow::IsTopLevelMouseExit(HWND aWnd)
+{
+ HWND mouseWnd = WindowAtMouse();
// WinUtils::GetTopLevelHWND() will return a HWND for the window frame
// (which includes the non-client area). If the mouse has moved into
// the non-client area, we should treat it as a top-level exit.
HWND mouseTopLevel = WinUtils::GetTopLevelHWND(mouseWnd);
if (mouseWnd == mouseTopLevel)
return true;
@@ -5641,16 +5638,24 @@ nsWindow::ProcessMessage(UINT msg, WPARA
break;
case WM_MOUSELEAVE:
{
if (!mMousePresent)
break;
mMousePresent = false;
+ // Check if the mouse is over the fullscreen transition window, if so
+ // clear sLastMouseMovePoint. This way the WM_MOUSEMOVE we get after the
+ // transition window disappears will not be ignored, even if the mouse
+ // hasn't moved.
+ if (mTransitionWnd && WindowAtMouse() == mTransitionWnd) {
+ sLastMouseMovePoint = {0};
+ }
+
// We need to check mouse button states and put them in for
// wParam.
WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
| (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
| (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
// Synthesize an event position because we don't get one from
// WM_MOUSELEAVE.
LPARAM pos = lParamToClient(::GetMessagePos());
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -151,16 +151,17 @@ public:
uint32_t aHotspotX, uint32_t aHotspotY) override;
virtual void SetCursor(nsCursor aCursor) override;
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;
virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
uint16_t aDuration,
nsISupports* aData,
nsIRunnable* aCallback) override;
+ virtual void CleanupFullscreenTransition() override;
virtual nsresult MakeFullScreen(bool aFullScreen,
nsIScreen* aScreen = nullptr) override;
virtual void HideWindowChrome(bool aShouldHide) override;
virtual void Invalidate(bool aEraseBackground = false,
bool aUpdateNCArea = false,
bool aIncludeChildren = false);
virtual void Invalidate(const LayoutDeviceIntRect& aRect);
virtual void* GetNativeData(uint32_t aDataType) override;
@@ -488,16 +489,17 @@ protected:
static bool IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult);
void IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam);
/**
* Misc.
*/
void StopFlashing();
+ static HWND WindowAtMouse();
static bool IsTopLevelMouseExit(HWND aWnd);
virtual nsresult SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
bool aIntersectWithExisting) override;
LayoutDeviceIntRegion GetRegionToPaint(bool aForceFullRepaint,
PAINTSTRUCT ps, HDC aDC);
void ClearCachedResources();
nsIWidgetListener* GetPaintListener();
@@ -667,20 +669,13 @@ protected:
RefPtr<mozilla::widget::WinCompositorWidget> mBasicLayersSurface;
static bool sNeedsToInitMouseWheelSettings;
static void InitMouseWheelScrollData();
double mSizeConstraintsScale; // scale in effect when setting constraints
- // Used to remember the wParam (i.e. currently pressed modifier keys)
- // and lParam (i.e. last mouse position) in screen coordinates from
- // the previous mouse-exit. Static since it is not
- // associated with a particular widget (since we exited the widget).
- static WPARAM sMouseExitwParam;
- static LPARAM sMouseExitlParamScreen;
-
// Pointer events processing and management
WinPointerEvents mPointerEvents;
};
#endif // Window_h__