This commit is contained in:
Ms2ger 2013-12-31 10:19:24 +01:00
Родитель fc0c5d7215 156b2e17c0
Коммит 26f2a85534
3 изменённых файлов: 176 добавлений и 129 удалений

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

@ -5,3 +5,4 @@ support-files = head.js
[browser_first_download_panel.js]
skip-if = os == "linux" # Bug 949434
[browser_overflow_anchor.js]
skip-if = os == "linux" # Bug 952422

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

@ -5180,18 +5180,15 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
}
}
break;
case WM_MOUSEACTIVATE:
if (mWindowType == eWindowType_popup) {
// a popup with a parent owner should not be activated when clicked
// but should still allow the mouse event to be fired, so the return
// value is set to MA_NOACTIVATE. But if the owner isn't the frontmost
// window, just use default processing so that the window is activated.
HWND owner = ::GetWindow(mWnd, GW_OWNER);
if (owner && owner == ::GetForegroundWindow()) {
*aRetValue = MA_NOACTIVATE;
result = true;
}
// A popup with a parent owner should not be activated when clicked but
// should still allow the mouse event to be fired, so the return value
// is set to MA_NOACTIVATE. But if the owner isn't the frontmost window,
// just use default processing so that the window is activated.
if (IsPopup() && IsOwnerForegroundWindow()) {
*aRetValue = MA_NOACTIVATE;
result = true;
}
break;
@ -7259,15 +7256,11 @@ static bool IsDifferentThreadWindow(HWND aWnd)
return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, nullptr);
}
// static
bool
nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
nsWindow::EventIsInsideWindow(nsWindow* aWindow)
{
RECT r;
if (Msg == WM_ACTIVATEAPP)
// don't care about activation/deactivation
return false;
::GetWindowRect(aWindow->mWnd, &r);
DWORD pos = ::GetMessagePos();
POINT mp;
@ -7275,141 +7268,178 @@ nsWindow::EventIsInsideWindow(UINT Msg, nsWindow* aWindow)
mp.y = GET_Y_LPARAM(pos);
// was the event inside this window?
return (bool) PtInRect(&r, mp);
return static_cast<bool>(::PtInRect(&r, mp));
}
// Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
// static
bool
nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
nsWindow::GetPopupsToRollup(nsIRollupListener* aRollupListener,
uint32_t* aPopupsToRollup)
{
NS_ASSERTION(outResult, "Bad outResult");
// If we're dealing with menus, we probably have submenus and we don't want
// to rollup some of them if the click is in a parent menu of the current
// submenu.
*aPopupsToRollup = UINT32_MAX;
nsAutoTArray<nsIWidget*, 5> widgetChain;
uint32_t sameTypeCount =
aRollupListener->GetSubmenuWidgetChain(&widgetChain);
for (uint32_t i = 0; i < widgetChain.Length(); ++i) {
nsIWidget* widget = widgetChain[i];
if (EventIsInsideWindow(static_cast<nsWindow*>(widget))) {
// Don't roll up if the mouse event occurred within a menu of the
// same type. If the mouse event occurred in a menu higher than that,
// roll up, but pass the number of popups to Rollup so that only those
// of the same type close up.
if (i < sameTypeCount) {
return false;
}
*outResult = MA_NOACTIVATE;
*aPopupsToRollup = sameTypeCount;
break;
}
}
return true;
}
if (!::IsWindowVisible(inWnd))
// static
bool
nsWindow::DealWithPopups(HWND aWnd, UINT aMessage,
WPARAM aWParam, LPARAM aLParam, LRESULT* aResult)
{
NS_ASSERTION(aResult, "Bad outResult");
// XXX Why do we use the return value of WM_MOUSEACTIVATE for all messages?
*aResult = MA_NOACTIVATE;
if (!::IsWindowVisible(aWnd)) {
return false;
}
nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
NS_ENSURE_TRUE(rollupListener, false);
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
if (!rollupWidget)
nsCOMPtr<nsIWidget> popup = rollupListener->GetRollupWidget();
if (!popup) {
return false;
}
inMsg = WinUtils::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)) ||
inMsg == WM_NCRBUTTONDOWN ||
inMsg == WM_MOVING ||
inMsg == WM_SIZING ||
inMsg == WM_NCLBUTTONDOWN ||
inMsg == WM_NCMBUTTONDOWN ||
inMsg == WM_MOUSEACTIVATE ||
inMsg == WM_ACTIVATEAPP ||
inMsg == WM_MENUSELECT) {
// Rollup if the event is outside the popup.
bool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)(rollupWidget.get()));
uint32_t popupsToRollup = UINT32_MAX;
if (rollup && (inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL)) {
rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
*outResult = MA_ACTIVATE;
}
nsWindow* popupWindow = static_cast<nsWindow*>(popup.get());
UINT nativeMessage = WinUtils::GetNativeMessage(aMessage);
switch (nativeMessage) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_NCLBUTTONDOWN:
case WM_NCRBUTTONDOWN:
case WM_NCMBUTTONDOWN:
if (!EventIsInsideWindow(popupWindow) &&
GetPopupsToRollup(rollupListener, &popupsToRollup)) {
break;
}
return false;
// If we're dealing with menus, we probably have submenus and we don't
// want to rollup if the click is in a parent menu of the current submenu.
uint32_t popupsToRollup = UINT32_MAX;
if (rollup) {
nsAutoTArray<nsIWidget*, 5> widgetChain;
uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
for ( uint32_t i = 0; i < widgetChain.Length(); ++i ) {
nsIWidget* widget = widgetChain[i];
if ( nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)widget) ) {
// don't roll up if the mouse event occurred within a menu of the
// same type. If the mouse event occurred in a menu higher than
// that, roll up, but pass the number of popups to Rollup so
// that only those of the same type close up.
if (i < sameTypeCount) {
rollup = false;
} else {
popupsToRollup = sameTypeCount;
}
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
// We need to check if the popup thinks that it should cause closing
// itself when mouse wheel events are fired outside the rollup widget.
if (!EventIsInsideWindow(popupWindow)) {
*aResult = MA_ACTIVATE;
if (rollupListener->ShouldRollupOnMouseWheelEvent() &&
GetPopupsToRollup(rollupListener, &popupsToRollup)) {
break;
}
} // foreach parent menu widget
}
}
return false;
case WM_ACTIVATEAPP:
break;
case WM_ACTIVATE:
// XXX Why do we need to check the message pos?
if (!EventIsInsideWindow(popupWindow) &&
GetPopupsToRollup(rollupListener, &popupsToRollup)) {
break;
}
return false;
case WM_MOUSEACTIVATE:
// XXX Why do we need to check the message pos?
if (!EventIsInsideWindow(popupWindow) &&
GetPopupsToRollup(rollupListener, &popupsToRollup)) {
// WM_MOUSEACTIVATE may be caused by moving the mouse (e.g., X-mouse
// of TweakUI is enabled. Then, check if the popup should be rolled up
// with rollup listener. If not, just consume the message.
if (HIWORD(aLParam) == WM_MOUSEMOVE &&
!rollupListener->ShouldRollupOnMouseActivate()) {
return true;
}
// Otherwise, it should be handled by wndproc.
return false;
}
if (inMsg == WM_MOUSEACTIVATE) {
// Prevent the click inside the popup from causing a change in window
// activation. Since the popup is shown non-activated, we need to eat
// any requests to activate the window while it is displayed. Windows
// will automatically activate the popup on the mousedown otherwise.
if (!rollup) {
return true;
} else {
UINT uMsg = HIWORD(inLParam);
if (uMsg == WM_MOUSEMOVE) {
// WM_MOUSEACTIVATE cause by moving the mouse - X-mouse (eg. TweakUI)
// must be enabled in Windows.
rollup = rollupListener->ShouldRollupOnMouseActivate();
if (!rollup) {
return true;
}
// activation. Since the popup is shown non-activated, we need to eat any
// requests to activate the window while it is displayed. Windows will
// automatically activate the popup on the mousedown otherwise.
return true;
case WM_KILLFOCUS:
// If focus moves to other window created in different process/thread,
// e.g., a plugin window, popups should be rolled up.
if (IsDifferentThreadWindow(reinterpret_cast<HWND>(aWParam))) {
// XXX Why do we need to check the message pos?
if (!EventIsInsideWindow(popupWindow) &&
GetPopupsToRollup(rollupListener, &popupsToRollup)) {
break;
}
}
}
// if we've still determined that we should still rollup everything, do it.
else if (rollup) {
// only need to deal with the last rollup for left mouse down events.
NS_ASSERTION(!mLastRollup, "mLastRollup is null");
return false;
bool consumeRollupEvent;
if (inMsg == WM_LBUTTONDOWN) {
POINT pt;
pt.x = GET_X_LPARAM(inLParam);
pt.y = GET_Y_LPARAM(inLParam);
::ClientToScreen(inWnd, &pt);
nsIntPoint pos(pt.x, pt.y);
consumeRollupEvent = rollupListener->Rollup(popupsToRollup, &pos, &mLastRollup);
NS_IF_ADDREF(mLastRollup);
}
else {
consumeRollupEvent = rollupListener->Rollup(popupsToRollup, nullptr, nullptr);
case WM_MOVING:
case WM_SIZING:
case WM_MENUSELECT:
// XXX Why do we need to check the message pos?
if (!EventIsInsideWindow(popupWindow) &&
GetPopupsToRollup(rollupListener, &popupsToRollup)) {
break;
}
return false;
// Tell hook to stop processing messages
sProcessHook = false;
sRollupMsgId = 0;
sRollupMsgWnd = nullptr;
default:
return false;
}
// return TRUE tells Windows that the event is consumed,
// false allows the event to be dispatched
//
// So if we are NOT supposed to be consuming events, let it go through
if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
*outResult = MA_ACTIVATE;
// Only need to deal with the last rollup for left mouse down events.
NS_ASSERTION(!mLastRollup, "mLastRollup is null");
// However, don't activate panels
if (inMsg == WM_MOUSEACTIVATE) {
nsWindow* activateWindow = WinUtils::GetNSWindowPtr(inWnd);
if (activateWindow) {
nsWindowType wintype;
activateWindow->GetWindowType(wintype);
if (wintype == eWindowType_popup && activateWindow->PopupType() == ePopupTypePanel) {
*outResult = popupsToRollup != UINT32_MAX ? MA_NOACTIVATEANDEAT : MA_NOACTIVATE;
}
}
}
return true;
}
// if we are only rolling up some popups, don't activate and don't let
// the event go through. This prevents clicks menus higher in the
// chain from opening when a context menu is open
if (popupsToRollup != UINT32_MAX && inMsg == WM_MOUSEACTIVATE) {
*outResult = MA_NOACTIVATEANDEAT;
return true;
}
}
} // if event that might trigger a popup to rollup
bool consumeRollupEvent;
if (nativeMessage == WM_LBUTTONDOWN) {
POINT pt;
pt.x = GET_X_LPARAM(aLParam);
pt.y = GET_Y_LPARAM(aLParam);
::ClientToScreen(aWnd, &pt);
nsIntPoint pos(pt.x, pt.y);
consumeRollupEvent =
rollupListener->Rollup(popupsToRollup, &pos, &mLastRollup);
NS_IF_ADDREF(mLastRollup);
} else {
consumeRollupEvent =
rollupListener->Rollup(popupsToRollup, nullptr, nullptr);
}
// Tell hook to stop processing messages
sProcessHook = false;
sRollupMsgId = 0;
sRollupMsgWnd = nullptr;
// If we are NOT supposed to be consuming events, let it go through
if (consumeRollupEvent && nativeMessage != WM_RBUTTONDOWN) {
*aResult = MA_ACTIVATE;
return true;
}
return false;
}

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

@ -337,6 +337,20 @@ protected:
return mTransparencyMode == eTransparencyGlass ||
mTransparencyMode == eTransparencyBorderlessGlass;
}
HWND GetOwnerWnd() const
{
return ::GetWindow(mWnd, GW_OWNER);
}
bool IsOwnerForegroundWindow() const
{
HWND owner = GetOwnerWnd();
return owner && owner == ::GetForegroundWindow();
}
bool IsPopup() const
{
return mWindowType == eWindowType_popup;
}
/**
* Event processing helpers
@ -358,7 +372,7 @@ protected:
bool *aEventDispatched);
LRESULT ProcessKeyDownMessage(const MSG &aMsg,
bool *aEventDispatched);
static bool EventIsInsideWindow(UINT Msg, nsWindow* aWindow);
static bool EventIsInsideWindow(nsWindow* aWindow);
// Convert nsEventStatus value to a windows boolean
static bool ConvertStatus(nsEventStatus aStatus);
static void PostSleepWakeNotification(const bool aIsSleepMode);
@ -405,6 +419,8 @@ protected:
static void ScheduleHookTimer(HWND aWnd, UINT aMsgId);
static void RegisterSpecialDropdownHooks();
static void UnregisterSpecialDropdownHooks();
static bool GetPopupsToRollup(nsIRollupListener* aRollupListener,
uint32_t* aPopupsToRollup);
static bool DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult);
/**