Bug 672175 part.14 Move WM_MOUSE*WHEEL and WM_*SCROLL handlers into MouseScrollHandler r=jimm

This commit is contained in:
Masayuki Nakano 2012-03-06 12:20:29 +09:00
Родитель 6adeee5400
Коммит 4103a35408
5 изменённых файлов: 268 добавлений и 191 удалений

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

@ -141,6 +141,25 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg,
}
return false;
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
GetInstance()->
ProcessNativeMouseWheelMessage(aWindow, msg, wParam, lParam);
// We don't need to call next wndproc for WM_MOUSEWHEEL and
// WM_MOUSEHWHEEL. We should consume them always. If the messages
// would be handled by our window again, it caused making infinite
// message loop.
aEatMessage = true;
*aRetValue = (msg != WM_MOUSEHWHEEL);
return true;
case WM_HSCROLL:
case WM_VSCROLL:
aEatMessage =
GetInstance()->ProcessNativeScrollMessage(aWindow, msg, wParam, lParam);
*aRetValue = 0;
return true;
case MOZ_WM_MOUSEVWHEEL:
case MOZ_WM_MOUSEHWHEEL:
GetInstance()->HandleMouseWheelMessage(aWindow, msg, wParam, lParam);
@ -304,6 +323,202 @@ MouseScrollHandler::GetScrollTargetInfo(
return result;
}
void
MouseScrollHandler::ProcessNativeMouseWheelMessage(nsWindow* aWindow,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam)
{
POINT point = ComputeMessagePos(aMessage, aWParam, aLParam);
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: aWindow=%p, "
"aMessage=%s, wParam=0x%08X, lParam=0x%08X, point: { x=%d, y=%d }",
aWindow, aMessage == WM_MOUSEWHEEL ? "WM_MOUSEWHEEL" :
aMessage == WM_MOUSEHWHEEL ? "WM_MOUSEHWHEEL" :
aMessage == WM_VSCROLL ? "WM_VSCROLL" : "WM_HSCROLL",
aWParam, aLParam, point.x, point.y));
LOG_KEYSTATE();
HWND underCursorWnd = ::WindowFromPoint(point);
if (!underCursorWnd) {
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: "
"No window is not found under the cursor"));
return;
}
if (Device::Elantech::IsPinchHackNeeded() &&
Device::Elantech::IsHelperWindow(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.
underCursorWnd = WinUtils::FindOurWindowAtPoint(point);
if (!underCursorWnd) {
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: "
"Our window is not found under the Elantech helper window"));
return;
}
}
// 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 (WinUtils::IsOurProcessWindow(underCursorWnd)) {
nsWindow* destWindow = WinUtils::GetNSWindowPtr(underCursorWnd);
if (!destWindow) {
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: "
"Found window under the cursor isn't managed by nsWindow..."));
HWND wnd = ::GetParent(underCursorWnd);
for (; wnd; wnd = ::GetParent(wnd)) {
destWindow = WinUtils::GetNSWindowPtr(wnd);
if (destWindow) {
break;
}
}
if (!wnd) {
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: Our window which is "
"managed by nsWindow is not found under the cursor"));
return;
}
}
MOZ_ASSERT(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. However, note that the DOM event may
// cause accessing the plugin. Therefore, we should unlock the plugin
// process by using PostMessage().
if (destWindow->GetWindowType() == eWindowType_plugin) {
destWindow = destWindow->GetParentWindow(false);
if (!destWindow) {
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: "
"Our window which is a parent of a plugin window is not found"));
return;
}
}
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, "
"Posting internal message to an nsWindow (%p)...",
destWindow));
UINT internalMessage = WinUtils::GetInternalMessage(aMessage);
::PostMessage(destWindow->GetWindowHandle(), internalMessage,
aWParam, aLParam);
return;
}
// 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 = WinUtils::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.
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: "
"Our window is not found under the cursor"));
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. However, note that the DOM event may cause accessing
// the plugin. Therefore, we should unlock the plugin process by using
// PostMessage().
if (aWindow->GetWindowType() == eWindowType_plugin &&
aWindow->GetWindowHandle() == pluginWnd) {
nsWindow* destWindow = aWindow->GetParentWindow(false);
if (!destWindow) {
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: Our normal window which "
"is a parent of this plugin window is not found"));
return;
}
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, "
"Posting internal message to an nsWindow (%p) which is parent of this "
"plugin window...",
destWindow));
UINT internalMessage = WinUtils::GetInternalMessage(aMessage);
::PostMessage(destWindow->GetWindowHandle(), internalMessage,
aWParam, aLParam);
return;
}
// If the window is a part of plugin, we should post the message to it.
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, "
"Redirecting the message to a window which is a plugin child window"));
::PostMessage(underCursorWnd, aMessage, aWParam, aLParam);
}
bool
MouseScrollHandler::ProcessNativeScrollMessage(nsWindow* aWindow,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam)
{
if (aLParam || mUserPrefs.IsScrollMessageHandledAsWheelMessage()) {
// Scroll message generated by Thinkpad Trackpoint Driver or similar
// Treat as a mousewheel message and scroll appropriately
ProcessNativeMouseWheelMessage(aWindow, aMessage, aWParam, aLParam);
// Always consume the scroll message if we try to emulate mouse wheel
// action.
return true;
}
PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS,
("MouseScroll::ProcessNativeScrollMessage: aWindow=%p, "
"aMessage=%s, wParam=0x%08X, lParam=0x%08X",
aWindow, aMessage == WM_VSCROLL ? "WM_VSCROLL" : "WM_HSCROLL",
aWParam, aLParam));
// Scroll message generated by external application
nsContentCommandEvent commandEvent(true, NS_CONTENT_COMMAND_SCROLL, aWindow);
commandEvent.mScroll.mIsHorizontal = (aMessage == WM_HSCROLL);
switch (LOWORD(aWParam)) {
case SB_LINEUP: // SB_LINELEFT
commandEvent.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
commandEvent.mScroll.mAmount = -1;
break;
case SB_LINEDOWN: // SB_LINERIGHT
commandEvent.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
commandEvent.mScroll.mAmount = 1;
break;
case SB_PAGEUP: // SB_PAGELEFT
commandEvent.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
commandEvent.mScroll.mAmount = -1;
break;
case SB_PAGEDOWN: // SB_PAGERIGHT
commandEvent.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
commandEvent.mScroll.mAmount = 1;
break;
case SB_TOP: // SB_LEFT
commandEvent.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
commandEvent.mScroll.mAmount = -1;
break;
case SB_BOTTOM: // SB_RIGHT
commandEvent.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
commandEvent.mScroll.mAmount = 1;
break;
default:
return false;
}
// XXX If this is a plugin window, we should dispatch the event from
// parent window.
DispatchEvent(aWindow, commandEvent);
return true;
}
void
MouseScrollHandler::HandleMouseWheelMessage(nsWindow* aWindow,
UINT aMessage,

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

@ -35,21 +35,6 @@ public:
LRESULT *aRetValue,
bool &aEatMessage);
/**
* ComputeMessagePos() computes the cursor position when the message was
* added to the queue.
*
* @param aMessage Handling message.
* @param aWParam Handling message's wParam.
* @param aLParam Handling message's lParam.
* @return Mouse cursor position when the message is added to
* the queue or current cursor position if the result of
* ::GetMessagePos() is broken.
*/
POINT ComputeMessagePos(UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
private:
MouseScrollHandler();
~MouseScrollHandler();
@ -72,6 +57,42 @@ private:
*/
static nsModifierKeyState GetModifierKeyState(UINT aMessage);
/**
* ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
* WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
* should be processed as mouse wheel message.
* This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
* MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
* events. That avoids deadlock with plugin process.
*
* @param aWindow A window which receives the message.
* @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
* WM_HSCROLL.
* @param aWParam The wParam value of the message.
* @param aLParam The lParam value of the message.
*/
void ProcessNativeMouseWheelMessage(nsWindow* aWindow,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
/**
* ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
* This method just call ProcessMouseWheelMessage() if the message should be
* processed as mouse wheel message. Otherwise, dispatches a content
* command event.
*
* @param aWindow A window which receives the message.
* @param aMessage WM_VSCROLL or WM_HSCROLL.
* @param aWParam The wParam value of the message.
* @param aLParam The lParam value of the message.
* @return TRUE if the message is processed. Otherwise, FALSE.
*/
bool ProcessNativeScrollMessage(nsWindow* aWindow,
UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
/**
* HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
* MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
@ -103,6 +124,21 @@ private:
WPARAM aWParam,
LPARAM aLParam);
/**
* ComputeMessagePos() computes the cursor position when the message was
* added to the queue.
*
* @param aMessage Handling message.
* @param aWParam Handling message's wParam.
* @param aLParam Handling message's lParam.
* @return Mouse cursor position when the message is added to
* the queue or current cursor position if the result of
* ::GetMessagePos() is broken.
*/
POINT ComputeMessagePos(UINT aMessage,
WPARAM aWParam,
LPARAM aLParam);
class EventInfo;
/**
* GetScrollTargetInfo() returns scroll target information which is
@ -279,7 +315,6 @@ private:
SystemSettings mSystemSettings;
public:
class UserPrefs {
public:
UserPrefs();
@ -313,12 +348,6 @@ public:
bool mScrollMessageHandledAsWheelMessage;
};
UserPrefs& GetUserPrefs()
{
return mUserPrefs;
}
private:
UserPrefs mUserPrefs;
public:

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

@ -5056,12 +5056,6 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
}
break;
case WM_HSCROLL:
case WM_VSCROLL:
*aRetValue = 0;
result = OnScroll(msg, wParam, lParam);
break;
// 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
@ -5206,14 +5200,6 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
}
break;
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 true;
case WM_DWMCOMPOSITIONCHANGED:
// First, update the compositor state to latest one. All other methods
// should use same state as here for consistency painting.
@ -7030,158 +7016,6 @@ bool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam)
return true;
}
/**
* 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;
MouseScrollHandler* handler = MouseScrollHandler::GetInstance();
POINT point = handler->ComputeMessagePos(aMsg, aWParam, aLParam);
HWND underCursorWnd = ::WindowFromPoint(point);
if (!underCursorWnd) {
return;
}
if (MouseScrollHandler::Device::Elantech::IsPinchHackNeeded() &&
MouseScrollHandler::Device::Elantech::IsHelperWindow(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.
underCursorWnd = WinUtils::FindOurWindowAtPoint(point);
if (!underCursorWnd) {
return;
}
}
// 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 (WinUtils::IsOurProcessWindow(underCursorWnd)) {
nsWindow* destWindow = WinUtils::GetNSWindowPtr(underCursorWnd);
if (!destWindow) {
NS_WARNING("We're not sure what cause this is.");
HWND wnd = ::GetParent(underCursorWnd);
for (; wnd; wnd = ::GetParent(wnd)) {
destWindow = WinUtils::GetNSWindowPtr(wnd);
if (destWindow) {
break;
}
}
if (!wnd) {
return;
}
}
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. However, note that the DOM event may
// cause accessing the plugin. Therefore, we should unlock the plugin
// process by using PostMessage().
if (destWindow->mWindowType == eWindowType_plugin) {
destWindow = destWindow->GetParentWindow(false);
NS_ENSURE_TRUE(destWindow, );
}
UINT internalMessage = WinUtils::GetInternalMessage(aMsg);
::PostMessage(destWindow->mWnd, internalMessage, aWParam, aLParam);
return;
}
// 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 = WinUtils::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. However, note that the DOM event may cause accessing
// the plugin. Therefore, we should unlock the plugin process by using
// PostMessage().
if (mWindowType == eWindowType_plugin && pluginWnd == mWnd) {
nsWindow* destWindow = GetParentWindow(false);
NS_ENSURE_TRUE(destWindow, );
UINT internalMessage = WinUtils::GetInternalMessage(aMsg);
::PostMessage(destWindow->mWnd, internalMessage, aWParam, aLParam);
return;
}
// If the window is a part of plugin, we should post the message to it.
::PostMessage(underCursorWnd, aMsg, aWParam, aLParam);
}
/**
* OnScroll() is called when ProcessMessage() handles WM_VSCROLL or WM_HSCROLL.
* aMsg may be WM_VSCROLL or WM_HSCROLL.
*/
bool
nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
{
if (aLParam ||
MouseScrollHandler::GetInstance()->
GetUserPrefs().IsScrollMessageHandledAsWheelMessage()) {
// Scroll message generated by Thinkpad Trackpoint Driver or similar
// Treat as a mousewheel message and scroll appropriately
LRESULT retVal;
OnMouseWheel(aMsg, aWParam, aLParam, &retVal);
// Always consume the scroll message if we try to emulate mouse wheel
// action.
return true;
}
// Scroll message generated by external application
nsContentCommandEvent command(true, NS_CONTENT_COMMAND_SCROLL, this);
command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
switch (LOWORD(aWParam))
{
case SB_LINEUP: // SB_LINELEFT
command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
command.mScroll.mAmount = -1;
break;
case SB_LINEDOWN: // SB_LINERIGHT
command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Line;
command.mScroll.mAmount = 1;
break;
case SB_PAGEUP: // SB_PAGELEFT
command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
command.mScroll.mAmount = -1;
break;
case SB_PAGEDOWN: // SB_PAGERIGHT
command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Page;
command.mScroll.mAmount = 1;
break;
case SB_TOP: // SB_LEFT
command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
command.mScroll.mAmount = -1;
break;
case SB_BOTTOM: // SB_RIGHT
command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
command.mScroll.mAmount = 1;
break;
default:
return false;
}
// XXX If this is a plugin window, we should dispatch the event from
// parent window.
DispatchWindowEvent(&command);
return true;
}
// Can be overriden. Controls auto-erase of background.
bool nsWindow::AutoErase(HDC dc)
{

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

@ -396,15 +396,12 @@ protected:
PRUint32 aFlags = 0,
const MSG *aMsg = nsnull,
bool *aEventDispatched = nsnull);
bool OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
bool OnGesture(WPARAM wParam, LPARAM lParam);
bool OnTouch(WPARAM wParam, LPARAM lParam);
bool OnHotKey(WPARAM wParam, LPARAM lParam);
BOOL OnInputLangChange(HKL aHKL);
bool OnPaint(HDC aDC, PRUint32 aNestingLevel);
void OnWindowPosChanged(WINDOWPOS *wp, bool& aResult);
void OnMouseWheel(UINT aMsg, WPARAM aWParam,
LPARAM aLParam, LRESULT *aRetValue);
void OnWindowPosChanging(LPWINDOWPOS& info);
void OnSysColorChanged();

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

@ -237,6 +237,8 @@ public:
bool Destroyed() { return mOnDestroyCalled; }
nsWindowType GetWindowType() { return mWindowType; }
protected:
virtual void ResolveIconName(const nsAString &aIconName,