From 53663750f706fed78b9f538dd42029a13f59436f Mon Sep 17 00:00:00 2001 From: Chris H-C Date: Fri, 20 Nov 2015 07:42:00 +0100 Subject: [PATCH] Bug 506815 - Replace MouseTrailer with TrackMouseEvent. r=jimm MouseTrailer, using a 200ms timer, was used to track whether a pointer was still present over a window. Windows has, since Windows 2000, offered to do this for us via an API called TrackMouseEvent. (It'll also give us hover timings and non-client area versions if we want) I'm all for having Windows do the work for us, and it'll save us from waking up the main thread five times a second. --HG-- extra : rebase_source : 9e56fd40929257d847c5cddb8a998c3ca2381655 --- widget/windows/nsToolkit.cpp | 127 ----------------------------------- widget/windows/nsToolkit.h | 38 ----------- widget/windows/nsWindow.cpp | 35 +++------- 3 files changed, 9 insertions(+), 191 deletions(-) diff --git a/widget/windows/nsToolkit.cpp b/widget/windows/nsToolkit.cpp index e40a26e4021c..6c3cc0508e62 100644 --- a/widget/windows/nsToolkit.cpp +++ b/widget/windows/nsToolkit.cpp @@ -23,7 +23,6 @@ using namespace mozilla::widget; nsToolkit* nsToolkit::gToolkit = nullptr; HINSTANCE nsToolkit::mDllInstance = 0; -MouseTrailer* nsToolkit::gMouseTrailer; //------------------------------------------------------------------------- // @@ -37,8 +36,6 @@ nsToolkit::nsToolkit() #if defined(MOZ_STATIC_COMPONENT_LIBS) nsToolkit::Startup(GetModuleHandle(nullptr)); #endif - - gMouseTrailer = &mMouseTrailer; } @@ -50,7 +47,6 @@ nsToolkit::nsToolkit() nsToolkit::~nsToolkit() { MOZ_COUNT_DTOR(nsToolkit); - gMouseTrailer = nullptr; } void @@ -83,126 +79,3 @@ nsToolkit* nsToolkit::GetToolkit() return gToolkit; } - - -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -MouseTrailer::MouseTrailer() : mMouseTrailerWindow(nullptr), mCaptureWindow(nullptr), - mIsInCaptureMode(false), mEnabled(true) -{ -} -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -MouseTrailer::~MouseTrailer() -{ - DestroyTimer(); -} -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -void MouseTrailer::SetMouseTrailerWindow(HWND aWnd) -{ - if (mMouseTrailerWindow != aWnd && mTimer) { - // Make sure TimerProc is fired at least once for the old window - TimerProc(nullptr, nullptr); - } - mMouseTrailerWindow = aWnd; - CreateTimer(); -} - -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -void MouseTrailer::SetCaptureWindow(HWND aWnd) -{ - mCaptureWindow = aWnd; - if (mCaptureWindow) { - mIsInCaptureMode = true; - } -} - -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -nsresult MouseTrailer::CreateTimer() -{ - if (mTimer || !mEnabled) { - return NS_OK; - } - - nsresult rv; - mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - return mTimer->InitWithFuncCallback(TimerProc, nullptr, 200, - nsITimer::TYPE_REPEATING_SLACK); -} - -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -void MouseTrailer::DestroyTimer() -{ - if (mTimer) { - mTimer->Cancel(); - mTimer = nullptr; - } -} - -//------------------------------------------------------------------------- -// -// -//------------------------------------------------------------------------- -void MouseTrailer::TimerProc(nsITimer* aTimer, void* aClosure) -{ - MouseTrailer *mtrailer = nsToolkit::gMouseTrailer; - NS_ASSERTION(mtrailer, "MouseTrailer still firing after deletion!"); - - // Check to see if we are in mouse capture mode, - // Once capture ends we could still get back one more timer event. - // Capture could end outside our window. - // Also, for some reason when the mouse is on the frame it thinks that - // it is inside the window that is being captured. - if (mtrailer->mCaptureWindow) { - if (mtrailer->mCaptureWindow != mtrailer->mMouseTrailerWindow) { - return; - } - } else { - if (mtrailer->mIsInCaptureMode) { - // mMouseTrailerWindow could be bad from rolling over the frame, so clear - // it if we were capturing and now this is the first timer callback - // since we canceled the capture - mtrailer->mMouseTrailerWindow = nullptr; - mtrailer->mIsInCaptureMode = false; - return; - } - } - - if (mtrailer->mMouseTrailerWindow && ::IsWindow(mtrailer->mMouseTrailerWindow)) { - POINT mp; - DWORD pos = ::GetMessagePos(); - mp.x = GET_X_LPARAM(pos); - mp.y = GET_Y_LPARAM(pos); - HWND mouseWnd = ::WindowFromPoint(mp); - if (mtrailer->mMouseTrailerWindow != mouseWnd) { - // Notify someone that a mouse exit happened. - PostMessage(mtrailer->mMouseTrailerWindow, WM_MOUSELEAVE, 0, 0); - - // we are out of this window, destroy timer - mtrailer->DestroyTimer(); - mtrailer->mMouseTrailerWindow = nullptr; - } - } else { - mtrailer->DestroyTimer(); - mtrailer->mMouseTrailerWindow = nullptr; - } -} - diff --git a/widget/windows/nsToolkit.h b/widget/windows/nsToolkit.h index 2b4f5767c976..14bb22c1895e 100644 --- a/widget/windows/nsToolkit.h +++ b/widget/windows/nsToolkit.h @@ -20,41 +20,6 @@ #define GET_Y_LPARAM(pt) (short(HIWORD(pt))) #endif -/** - * Makes sure exit/enter mouse messages are always dispatched. - * In the case where the mouse has exited the outer most window the - * only way to tell if it has exited is to set a timer and look at the - * mouse pointer to see if it is within the outer most window. - */ - -class MouseTrailer -{ -public: - HWND GetMouseTrailerWindow() { return mMouseTrailerWindow; } - HWND GetCaptureWindow() { return mCaptureWindow; } - - void SetMouseTrailerWindow(HWND aWnd); - void SetCaptureWindow(HWND aWnd); - void Disable() { mEnabled = false; DestroyTimer(); } - void Enable() { mEnabled = true; CreateTimer(); } - void DestroyTimer(); - - MouseTrailer(); - ~MouseTrailer(); -private: - - nsresult CreateTimer(); - - static void TimerProc(nsITimer* aTimer, void* aClosure); - - // Information for mouse enter/exit events - HWND mMouseTrailerWindow; - HWND mCaptureWindow; - bool mIsInCaptureMode; - bool mEnabled; - nsCOMPtr mTimer; -}; - /** * Wrapper around the thread running the message pump. * The toolkit abstraction is necessary because the message pump must @@ -73,15 +38,12 @@ public: static nsToolkit* GetToolkit(); static HINSTANCE mDllInstance; - static MouseTrailer *gMouseTrailer; static void Startup(HMODULE hModule); static void Shutdown(); protected: static nsToolkit* gToolkit; - - MouseTrailer mMouseTrailer; }; #endif // TOOLKIT_H diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 72407a0d0625..dff3cc654464 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -3381,16 +3381,9 @@ NS_METHOD nsWindow::EnableDragDrop(bool aEnable) NS_METHOD nsWindow::CaptureMouse(bool aCapture) { - if (!nsToolkit::gMouseTrailer) { - NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed"); - return NS_OK; - } - if (aCapture) { - nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd); ::SetCapture(mWnd); } else { - nsToolkit::gMouseTrailer->SetCaptureWindow(nullptr); ::ReleaseCapture(); } sIsInMouseCapture = aCapture; @@ -4200,12 +4193,7 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam, // call the event callback if (mWidgetListener) { - if (nsToolkit::gMouseTrailer) - nsToolkit::gMouseTrailer->Disable(); if (aEventMessage == eMouseMove) { - if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) { - nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd); - } LayoutDeviceIntRect rect; GetBounds(rect); rect.x = 0; @@ -4238,9 +4226,6 @@ nsWindow::DispatchMouseEvent(EventMessage aEventMessage, WPARAM wParam, result = ConvertStatus(DispatchAPZAwareEvent(&event)); - if (nsToolkit::gMouseTrailer) - nsToolkit::gMouseTrailer->Enable(); - // Release the widget with NS_IF_RELEASE() just in case // the context menu key code in EventListenerManager::HandleEvent() // released it already. @@ -5093,6 +5078,15 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, case WM_MOUSEMOVE: { + if (!mMousePresent) { + // First MOOUSEMOVE over the client area. Ask for MOUSELEAVE + TRACKMOUSEEVENT mTrack; + mTrack.cbSize = sizeof(TRACKMOUSEEVENT); + mTrack.dwFlags = TME_LEAVE; + mTrack.dwHoverTime = 0; + mTrack.hwndTrack = mWnd; + TrackMouseEvent(&mTrack); + } mMousePresent = true; // Suppress dispatch of pending events @@ -6685,23 +6679,12 @@ void nsWindow::OnDestroy() IMEHandler::OnDestroyWindow(this); - // Turn off mouse trails if enabled. - MouseTrailer* mtrailer = nsToolkit::gMouseTrailer; - if (mtrailer) { - if (mtrailer->GetMouseTrailerWindow() == mWnd) - mtrailer->DestroyTimer(); - - if (mtrailer->GetCaptureWindow() == mWnd) - mtrailer->SetCaptureWindow(nullptr); - } - // Free GDI window class objects if (mBrush) { VERIFY(::DeleteObject(mBrush)); mBrush = nullptr; } - // Destroy any custom cursor resources. if (mCursor == -1) SetCursor(eCursor_standard);