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
This commit is contained in:
Chris H-C 2015-11-20 07:42:00 +01:00
Родитель 22151cf459
Коммит 53663750f7
3 изменённых файлов: 9 добавлений и 191 удалений

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -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<nsITimer> 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

Просмотреть файл

@ -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);