Bug 658194 Get rid of SendMessage() from mouse wheel event handling r=jimm

This commit is contained in:
Masayuki Nakano 2011-08-02 12:03:15 +09:00
parent 78624d4f58
commit a2e2baf3cd
4 changed files with 207 additions and 194 deletions

View File

@ -1289,10 +1289,6 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd,
if ((InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
switch(message) {
case WM_KILLFOCUS:
case WM_MOUSEHWHEEL:
case WM_MOUSEWHEEL:
case WM_HSCROLL:
case WM_VSCROLL:
ReplyMessage(0);
break;
}

View File

@ -4251,11 +4251,6 @@ nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam)
handled = PR_TRUE;
}
break;
// Wheel events forwarded from the child.
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_HSCROLL:
case WM_VSCROLL:
// Plugins taking or losing focus triggering focus app messages.
case WM_SETFOCUS:
case WM_KILLFOCUS:
@ -5123,6 +5118,13 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
result = OnScroll(msg, wParam, lParam);
break;
case MOZ_WM_HSCROLL:
case MOZ_WM_VSCROLL:
*aRetValue = 0;
OnScrollInternal(GetNativeMessage(msg), wParam, lParam);
// Doesn't need to call next wndproc for internal message.
return PR_TRUE;
// The WM_ACTIVATE event is fired when a window is raised or lowered,
// and the loword of wParam specifies which. But we don't want to tell
// the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
@ -5285,18 +5287,26 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
OnMouseWheel(msg, wParam, lParam, aRetValue);
// We don't need to call next wndproc WM_MOUSEWHEEL and WM_MOUSEHWHEEL.
// We should consume them always. If the messages would be handled by
// our window again, it causes making infinite message loop.
return PR_TRUE;
case MOZ_WM_MOUSEVWHEEL:
case MOZ_WM_MOUSEHWHEEL:
{
UINT nativeMessage = GetNativeMessage(msg);
// If OnMouseWheel returns true, the event was forwarded directly to another
// mozilla window message handler (ProcessMessage). In this case the return
// value of the forwarded event is in 'result' which we should return immediately.
// If OnMouseWheel returns false, OnMouseWheel processed the event internally.
// 'result' and 'aRetValue' will be set based on what we did with the event, so
// we should fall through.
if (OnMouseWheel(msg, wParam, lParam, result, aRetValue)) {
return result;
}
OnMouseWheelInternal(nativeMessage, wParam, lParam, aRetValue);
// Doesn't need to call next wndproc for internal message.
return PR_TRUE;
}
break;
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
case WM_DWMCOMPOSITIONCHANGED:
@ -6366,14 +6376,14 @@ static PRInt32 RoundDelta(double aDelta)
return aDelta >= 0 ? (PRInt32)NS_floor(aDelta) : (PRInt32)NS_ceil(aDelta);
}
/*
* OnMouseWheel - mouse wheel event processing. This was originally embedded
* within the message case block. If returning true result should be returned
* immediately (no more processing).
/**
* OnMouseWheelInternal - mouse wheel event processing.
* aMessage may be WM_MOUSEWHEEL or WM_MOUSEHWHEEL but this is called when
* ProcessMessage() handles MOZ_WM_MOUSEVWHEEL or MOZ_WM_MOUSEHWHEEL.
*/
PRBool
nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
PRBool& aHandled, LRESULT *aRetValue)
void
nsWindow::OnMouseWheelInternal(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
LRESULT *aRetValue)
{
InitMouseWheelScrollData();
@ -6385,31 +6395,16 @@ nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
// and web application may want to handle the event for non-scroll action.
ResetRemainingWheelDelta();
*aRetValue = isVertical ? TRUE : FALSE; // means we don't process it
aHandled = PR_FALSE;
return PR_FALSE;
return;
}
// The mousewheel event will be dispatched to the toplevel
// window. We need to give it to the child window.
PRBool quit;
if (!HandleScrollingPlugins(aMessage, aWParam, aLParam,
aHandled, aRetValue, quit)) {
ResetRemainingWheelDelta();
return quit; // return immediately if it's not our window
}
PRInt32 nativeDelta = (short)HIWORD(aWParam);
if (!nativeDelta) {
*aRetValue = isVertical ? TRUE : FALSE; // means we don't process it
aHandled = PR_FALSE;
ResetRemainingWheelDelta();
return PR_FALSE; // We cannot process this message
return; // We cannot process this message
}
// The event may go to a plug-in which already dispatched this message.
// Then, the event can cause deadlock. We should unlock the sender here.
::ReplyMessage(isVertical ? 0 : TRUE);
PRBool isPageScroll =
((isVertical && sMouseWheelScrollLines == WHEEL_PAGESCROLL) ||
(!isVertical && sMouseWheelScrollChars == WHEEL_PAGESCROLL));
@ -6556,17 +6551,17 @@ nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
}
if (scrollEvent.delta) {
aHandled = DispatchWindowEvent(&scrollEvent);
DispatchWindowEvent(&scrollEvent);
if (mOnDestroyCalled) {
ResetRemainingWheelDelta();
return PR_FALSE;
return;
}
}
// If the query event failed, we cannot send pixel events.
if (!dispatchPixelScrollEvent) {
sRemainingDeltaForPixel = 0;
return PR_FALSE;
return;
}
nsMouseScrollEvent pixelEvent(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
@ -6596,9 +6591,9 @@ nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
(PRInt32)(pixelEvent.delta * orienterForPixel * deltaPerPixel);
sRemainingDeltaForPixel = nativeDeltaForPixel - recomputedNativeDelta;
if (pixelEvent.delta != 0) {
aHandled = DispatchWindowEvent(&pixelEvent);
DispatchWindowEvent(&pixelEvent);
}
return PR_FALSE;
return;
}
static PRBool
@ -7582,28 +7577,59 @@ static PRBool IsElantechHelperWindow(HWND aHWND)
return result;
}
// Scrolling helper function for handling plugins.
// Return value indicates whether the calling function should handle this
// aHandled indicates whether this was handled at all
// aQuitProcessing tells whether or not to continue processing the message
PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
LPARAM aLParam, PRBool& aHandled,
LRESULT* aRetValue,
PRBool& aQuitProcessing)
// static
UINT
nsWindow::GetInternalMessage(UINT aNativeMessage)
{
// The scroll event will be dispatched to the toplevel
// window. We need to give it to the child window
aQuitProcessing = PR_FALSE; // default is to not stop processing
switch (aNativeMessage) {
case WM_MOUSEWHEEL:
return MOZ_WM_MOUSEVWHEEL;
case WM_MOUSEHWHEEL:
return MOZ_WM_MOUSEHWHEEL;
case WM_VSCROLL:
return MOZ_WM_VSCROLL;
case WM_HSCROLL:
return MOZ_WM_HSCROLL;
default:
return aNativeMessage;
}
}
// static
UINT
nsWindow::GetNativeMessage(UINT aInternalMessage)
{
switch (aInternalMessage) {
case MOZ_WM_MOUSEVWHEEL:
return WM_MOUSEWHEEL;
case MOZ_WM_MOUSEHWHEEL:
return WM_MOUSEHWHEEL;
case MOZ_WM_VSCROLL:
return WM_VSCROLL;
case MOZ_WM_HSCROLL:
return WM_HSCROLL;
default:
return aInternalMessage;
}
}
/**
* OnMouseWheel() is called when ProcessMessage() handles WM_MOUSEWHEEL,
* WM_MOUSEHWHEEL and also OnScroll() tries to emulate mouse wheel action for
* WM_VSCROLL or WM_HSCROLL.
* So, aMsg may be WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or WM_HSCROLL.
*/
void
nsWindow::OnMouseWheel(UINT aMsg, WPARAM aWParam, LPARAM aLParam,
LRESULT *aRetValue)
{
*aRetValue = (aMsg != WM_MOUSEHWHEEL) ? TRUE : FALSE;
POINT point;
DWORD dwPoints = ::GetMessagePos();
point.x = GET_X_LPARAM(dwPoints);
point.y = GET_Y_LPARAM(dwPoints);
static PRBool sIsProcessing = PR_FALSE;
if (sIsProcessing) {
return PR_TRUE; // the caller should handle this.
}
static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
if (aMsg == WM_MOUSEHWHEEL) {
// Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
@ -7630,109 +7656,86 @@ PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
}
}
HWND destWnd = ::WindowFromPoint(point);
// Since we receive scroll events for as long as
// we are focused, it's entirely possible that there
// is another app's window or no window under the
// pointer.
HWND underCursorWnd = ::WindowFromPoint(point);
if (!underCursorWnd) {
return;
}
if (sUseElantechPinchHack && IsElantechHelperWindow(destWnd)) {
if (sUseElantechPinchHack && IsElantechHelperWindow(underCursorWnd)) {
// The Elantech driver places a window right underneath the cursor
// when sending a WM_MOUSEWHEEL event to us as part of a pinch-to-zoom
// gesture. We detect that here, and search for our window that would
// be beneath the cursor if that window wasn't there.
destWnd = FindOurWindowAtPoint(point);
}
if (!destWnd) {
// No window is under the pointer
return PR_FALSE; // break, but continue processing
}
nsWindow* destWindow;
// We don't handle the message if the found window belongs to another
// process's top window. If it belongs window, that is a plug-in's window.
// Then, we need to send the message to the plug-in window.
if (!IsOurProcessWindow(destWnd)) {
HWND ourPluginWnd = FindOurProcessWindow(destWnd);
if (!ourPluginWnd) {
// Somebody elses window
return PR_FALSE; // break, but continue processing
underCursorWnd = FindOurWindowAtPoint(point);
if (!underCursorWnd) {
return;
}
destWindow = GetNSWindowPtr(ourPluginWnd);
} else {
destWindow = GetNSWindowPtr(destWnd);
}
if (destWindow == this && mWindowType == eWindowType_plugin) {
// If this is plug-in window, the message came from the plug-in window.
// Then, the message should be processed on the parent window.
destWindow = static_cast<nsWindow*>(GetParent());
NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
destWnd = destWindow->mWnd;
NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
}
if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
// Some other app, or a plugin window.
// Windows directs scrolling messages to the focused window.
// However, Mozilla does not like plugins having focus, so a
// Mozilla window (ie, the plugin's parent (us!) has focus.)
// Therefore, plugins etc _should_ get first grab at the
// message, but this focus vaguary means the plugin misses
// out. If the window is a child of ours, forward it on.
// Determine if a child by walking the parent list until
// we find a parent matching our wndproc.
HWND parentWnd = ::GetParent(destWnd);
while (parentWnd) {
nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
if (parentWindow) {
// We have a child window - quite possibly a plugin window.
// However, not all plugins are created equal - some will handle this
// message themselves, some will forward directly back to us, while
// others will call DefWndProc, which itself still forwards back to us.
// So if we have sent it once, we need to handle it ourself.
// XXX The message shouldn't come from the plugin window at here.
// But the message might come from it due to some bugs. If it happens,
// SendMessage causes deadlock. For safety, we should unlock the
// sender here.
::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
// First time we have seen this message.
// Call the child - either it will consume it, or
// it will wind it's way back to us,triggering the destWnd case above
// either way,when the call returns,we are all done with the message,
sIsProcessing = PR_TRUE;
::SendMessageW(destWnd, aMsg, aWParam, aLParam);
sIsProcessing = PR_FALSE;
aHandled = PR_TRUE;
aQuitProcessing = PR_TRUE;
return PR_FALSE; // break, and stop processing
// Handle most cases first. If the window under mouse cursor is our window
// except plugin window (MozillaWindowClass), we should handle the message
// on the window.
if (IsOurProcessWindow(underCursorWnd)) {
nsWindow* destWindow = GetNSWindowPtr(underCursorWnd);
if (!destWindow) {
NS_WARNING("We're not sure what cause this is.");
HWND wnd = ::GetParent(underCursorWnd);
for (; wnd; wnd = ::GetParent(wnd)) {
destWindow = GetNSWindowPtr(wnd);
if (destWindow) {
break;
}
}
if (!wnd) {
return;
}
parentWnd = ::GetParent(parentWnd);
} // while parentWnd
}
if (destWnd == nsnull)
return PR_FALSE;
if (destWnd != mWnd) {
if (destWindow) {
sIsProcessing = PR_TRUE;
aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
sIsProcessing = PR_FALSE;
aQuitProcessing = PR_TRUE;
return PR_FALSE; // break, and stop processing
}
#ifdef DEBUG
else
printf("WARNING: couldn't get child window for SCROLL event\n");
#endif
NS_ASSERTION(destWindow, "destWindow must not be NULL");
// If the found window is our plugin window, it means that the message
// has been handled by the plugin but not consumed. We should handle the
// message on its parent window.
if (destWindow->mWindowType == eWindowType_plugin) {
destWindow = destWindow->GetParentWindow(PR_FALSE);
NS_ENSURE_TRUE(destWindow, );
}
UINT internalMessage = GetInternalMessage(aMsg);
destWindow->ProcessMessage(internalMessage, aWParam, aLParam, aRetValue);
return;
}
return PR_TRUE; // caller should handle this
// If the window under cursor is not in our process, it means:
// 1. The window may be a plugin window (GeckoPluginWindow or its descendant).
// 2. The window may be another application's window.
HWND pluginWnd = FindOurProcessWindow(underCursorWnd);
if (!pluginWnd) {
// If there is no plugin window in ancestors of the window under cursor,
// the window is for another applications (case 2).
// We don't need to handle this message.
return;
}
// If we're a plugin window (MozillaWindowClass) and cursor in this window,
// the message shouldn't go to plugin's wndproc again. So, we should handle
// it on parent window.
if (mWindowType == eWindowType_plugin && pluginWnd == mWnd) {
nsWindow* destWindow = GetParentWindow(PR_FALSE);
NS_ENSURE_TRUE(destWindow, );
UINT internalMessage = GetInternalMessage(aMsg);
destWindow->ProcessMessage(internalMessage, aWParam, aLParam, aRetValue);
return;
}
// If the window is a part of plugin, we should post the message to it.
::PostMessage(underCursorWnd, aMsg, aWParam, aLParam);
}
PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
/**
* OnScroll() is called when ProcessMessage() handles WM_VSCROLL or WM_HSCROLL.
* aMsg may be WM_VSCROLL or WM_HSCROLL.
*/
PRBool
nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
{
static PRInt8 sMouseWheelEmulation = -1;
if (sMouseWheelEmulation < 0) {
@ -7744,43 +7747,10 @@ PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
if (aLParam || sMouseWheelEmulation) {
// Scroll message generated by Thinkpad Trackpoint Driver or similar
// Treat as a mousewheel message and scroll appropriately
PRBool quit, result;
LRESULT retVal;
if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
return quit; // Return if it's not our message or has been dispatched
nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
? nsMouseScrollEvent::kIsVertical
: nsMouseScrollEvent::kIsHorizontal;
switch (LOWORD(aWParam))
{
case SB_PAGEDOWN:
scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
case SB_LINEDOWN:
scrollevent.delta = 1;
break;
case SB_PAGEUP:
scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
case SB_LINEUP:
scrollevent.delta = -1;
break;
default:
return PR_FALSE;
}
// The event may go to a plug-in which already dispatched this message.
// Then, the event can cause deadlock. We should unlock the sender here.
::ReplyMessage(0);
scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
scrollevent.isMeta = PR_FALSE;
scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
InitEvent(scrollevent);
if (nsnull != mEventCallback)
{
DispatchWindowEvent(&scrollevent);
}
OnMouseWheel(aMsg, aWParam, aLParam, &retVal);
// Always consume the scroll message if we try to emulate mouse wheel
// action.
return PR_TRUE;
}
@ -7818,10 +7788,49 @@ PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
default:
return PR_FALSE;
}
// XXX If this is a plugin window, we should dispatch the event from
// parent window.
DispatchWindowEvent(&command);
return PR_TRUE;
}
/**
* OnScrollInternal() is called when ProcessMessage() handles MOZ_WM_VSCROLL or
* MOZ_WM_HSCROLL but aMsg may be WM_VSCROLL or WM_HSCROLL.
* These internal messages used only when OnScroll() tries to emulate mouse
* wheel action for the WM_VSCROLL or WM_HSCROLL message.
*/
void
nsWindow::OnScrollInternal(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
{
nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
scrollevent.scrollFlags = (aMsg == WM_VSCROLL)
? nsMouseScrollEvent::kIsVertical
: nsMouseScrollEvent::kIsHorizontal;
switch (LOWORD(aWParam)) {
case SB_PAGEDOWN:
scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
case SB_LINEDOWN:
scrollevent.delta = 1;
break;
case SB_PAGEUP:
scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
case SB_LINEUP:
scrollevent.delta = -1;
break;
default:
return;
}
scrollevent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
scrollevent.isMeta = PR_FALSE;
scrollevent.isAlt = IS_VK_DOWN(NS_VK_ALT);
InitEvent(scrollevent);
if (mEventCallback) {
DispatchWindowEvent(&scrollevent);
}
}
// Can be overriden. Controls auto-erase of background.
PRBool nsWindow::AutoErase(HDC dc)
{
@ -8389,7 +8398,7 @@ LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM l
LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
{
if (sProcessHook) {
switch (wParam) {
switch (GetNativeMessage(wParam)) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
@ -8590,6 +8599,7 @@ nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLPara
{
if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
inMsg = GetNativeMessage(inMsg);
if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
(inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam)) ||

View File

@ -375,11 +375,6 @@ protected:
// Convert nsEventStatus value to a windows boolean
static PRBool ConvertStatus(nsEventStatus aStatus);
static void PostSleepWakeNotification(const char* aNotification);
PRBool HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
LPARAM aLParam,
PRBool& aResult,
LRESULT* aRetValue,
PRBool& aQuitProcessing);
PRInt32 ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my);
static WORD GetScanCode(LPARAM aLParam)
{
@ -417,7 +412,9 @@ protected:
PRUint32 aFlags = 0,
const MSG *aMsg = nsnull,
PRBool *aEventDispatched = nsnull);
virtual PRBool OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
PRBool OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
void OnScrollInternal(UINT aMsg, WPARAM aWParam,
LPARAM aLParam);
PRBool OnGesture(WPARAM wParam, LPARAM lParam);
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
PRBool OnTouch(WPARAM wParam, LPARAM lParam);
@ -426,9 +423,13 @@ protected:
BOOL OnInputLangChange(HKL aHKL);
PRBool OnPaint(HDC aDC, PRUint32 aNestingLevel);
void OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult);
PRBool OnMouseWheel(UINT aMessage, WPARAM aWParam,
LPARAM aLParam, PRBool& aHandled,
LRESULT *aRetValue);
static UINT GetInternalMessage(UINT aNativeMessage);
static UINT GetNativeMessage(UINT aInternalMessage);
void OnMouseWheel(UINT aMsg, WPARAM aWParam,
LPARAM aLParam, LRESULT *aRetValue);
void OnMouseWheelInternal(UINT aMessage, WPARAM aWParam,
LPARAM aLParam,
LRESULT *aRetValue);
void OnWindowPosChanging(LPWINDOWPOS& info);
/**

View File

@ -58,6 +58,12 @@
#define MOZ_WM_APP_QUIT (WM_APP+0x0300)
// Used as a "tracer" event to probe event loop latency.
#define MOZ_WM_TRACE (WM_APP+0x0301)
// Our internal message for WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL and
// WM_HSCROLL
#define MOZ_WM_MOUSEVWHEEL (WM_APP+0x0310)
#define MOZ_WM_MOUSEHWHEEL (WM_APP+0x0311)
#define MOZ_WM_VSCROLL (WM_APP+0x0312)
#define MOZ_WM_HSCROLL (WM_APP+0x0313)
// GetWindowsVersion constants
#define WIN2K_VERSION 0x500