Bug 1437941: Don't ignore mousemove after fullscreen transition draft
authorAdam Gashlin <agashlin@mozilla.com>
Mon, 02 Apr 2018 18:42:12 -0700
changeset 776426 5298ce3034e5cb74dc11a49824ba7ebfe383ec06
parent 776387 445255800255bb13ed096b5b7da36aa835e41dd8
push id104876
push userbmo:agashlin@mozilla.com
push dateTue, 03 Apr 2018 01:45:23 +0000
bugs1437941
milestone61.0a1
Bug 1437941: Don't ignore mousemove after fullscreen transition MozReview-Commit-ID: Hr9dcKVeYEC
dom/base/nsGlobalWindowOuter.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- 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__