tdf#122920 Send UNO mouse events to parent window listeners as well

When user registers a mouse listener to a window, he expects
to receive mouse events when a user clicks in somewhere in that
window, even if it's technically a widget inside that window

Change-Id: Ie6d3f8b140e4a5b516051014282b43775ecec59e
Reviewed-on: https://gerrit.libreoffice.org/70512
Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
Tested-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
This commit is contained in:
Samuel Mehrbrodt
2019-04-10 11:21:32 +02:00
parent c650217cc5
commit 6f43902b12
2 changed files with 53 additions and 39 deletions

View File

@@ -43,15 +43,13 @@ class XMouseListenerExtended(unohelper.Base, XMouseListener):
# is invoked when the mouse enters a window. # is invoked when the mouse enters a window.
@classmethod @classmethod
def mouseEntered(self, xMouseEvent): def mouseEntered(self, xMouseEvent):
global mouseEventsIntercepted # doesn't work in UI tests
mouseEventsIntercepted += 1
return super(XMouseListenerExtended, self).mouseEntered(xMouseEvent) return super(XMouseListenerExtended, self).mouseEntered(xMouseEvent)
# is invoked when the mouse exits a window. # is invoked when the mouse exits a window.
@classmethod @classmethod
def mouseExited(self, xMouseEvent): def mouseExited(self, xMouseEvent):
global mouseEventsIntercepted # doesn't work in UI tests
mouseEventsIntercepted += 1
return super(XMouseListenerExtended, self).mouseExited(xMouseEvent) return super(XMouseListenerExtended, self).mouseExited(xMouseEvent)
@@ -142,8 +140,8 @@ class XWindow(UITestCase):
self.assertEqual(0, keymouseEventsIntercepted) self.assertEqual(0, keymouseEventsIntercepted)
global mouseEventsIntercepted global mouseEventsIntercepted
# Not expected 3 interceptions # mousePressed, mouseReleased and mouseEntered should be triggered
self.assertEqual(0, mouseEventsIntercepted) self.assertEqual(2, mouseEventsIntercepted)
# close document # close document
self.ui_test.close_doc() self.ui_test.close_doc()

View File

@@ -703,50 +703,66 @@ void VCLXWindow::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
case VclEventId::WindowMouseMove: case VclEventId::WindowMouseMove:
{ {
MouseEvent* pMouseEvt = static_cast<MouseEvent*>(rVclWindowEvent.GetData()); MouseEvent* pMouseEvt = static_cast<MouseEvent*>(rVclWindowEvent.GetData());
if ( mpImpl->getMouseListeners().getLength() && ( pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow() ) ) VclPtr<vcl::Window> pWin = GetWindow();
while (pWin)
{ {
awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( *pMouseEvt, *this ) ); VCLXWindow* pXWindow = pWin->GetWindowPeer();
bool const isEnter(pMouseEvt->IsEnterWindow()); if (!pXWindow || pXWindow->mpImpl->getMouseListeners().getLength() == 0)
Callback aCallback = [ this, isEnter, aEvent ]() {
{ MouseListenerMultiplexer& rMouseListeners = this->mpImpl->getMouseListeners(); pWin = pWin->GetWindow(GetWindowType::RealParent);
isEnter continue;
? rMouseListeners.mouseEntered(aEvent) }
: rMouseListeners.mouseExited(aEvent); }; awt::MouseEvent aEvent(VCLUnoHelper::createMouseEvent(*pMouseEvt, *pXWindow));
ImplExecuteAsyncWithoutSolarLock( aCallback ); if (pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow())
{
bool const isEnter(pMouseEvt->IsEnterWindow());
Callback aCallback = [pXWindow, isEnter, aEvent]() {
isEnter ? pXWindow->mpImpl->getMouseListeners().mouseEntered(aEvent)
: pXWindow->mpImpl->getMouseListeners().mouseExited(aEvent);
};
ImplExecuteAsyncWithoutSolarLock(aCallback);
}
else
{
aEvent.ClickCount = 0;
MouseMotionListenerMultiplexer& rMouseListeners
= pXWindow->mpImpl->getMouseMotionListeners();
if (pMouseEvt->GetMode() & MouseEventModifiers::SIMPLEMOVE)
rMouseListeners.mouseMoved(aEvent);
else
rMouseListeners.mouseDragged(aEvent);
} }
if ( mpImpl->getMouseMotionListeners().getLength() && !pMouseEvt->IsEnterWindow() && !pMouseEvt->IsLeaveWindow() ) // Next window (parent)
{ pWin = pWin->GetWindow(GetWindowType::RealParent);
awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( *pMouseEvt, *this ) );
aEvent.ClickCount = 0;
if ( pMouseEvt->GetMode() & MouseEventModifiers::SIMPLEMOVE )
mpImpl->getMouseMotionListeners().mouseMoved( aEvent );
else
mpImpl->getMouseMotionListeners().mouseDragged( aEvent );
} }
} }
break; break;
case VclEventId::WindowMouseButtonDown: case VclEventId::WindowMouseButtonDown:
{
if ( mpImpl->getMouseListeners().getLength() )
{
awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( *static_cast<MouseEvent*>(rVclWindowEvent.GetData()), *this ) );
Callback aCallback = [ this, aEvent ]()
{ this->mpImpl->getMouseListeners().mousePressed( aEvent ); };
ImplExecuteAsyncWithoutSolarLock( aCallback );
}
}
break;
case VclEventId::WindowMouseButtonUp: case VclEventId::WindowMouseButtonUp:
{ {
if ( mpImpl->getMouseListeners().getLength() ) VclPtr<vcl::Window> pWin = GetWindow();
while (pWin)
{ {
awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( *static_cast<MouseEvent*>(rVclWindowEvent.GetData()), *this ) ); VCLXWindow* pXWindow = pWin->GetWindowPeer();
if (!pXWindow || pXWindow->mpImpl->getMouseListeners().getLength() == 0)
{
pWin = pWin->GetWindow(GetWindowType::RealParent);
continue;
}
MouseEvent* pMouseEvt = static_cast<MouseEvent*>(rVclWindowEvent.GetData());
awt::MouseEvent aEvent(VCLUnoHelper::createMouseEvent(*pMouseEvt, *pXWindow));
VclEventId eventId = rVclWindowEvent.GetId();
Callback aCallback = [pXWindow, aEvent, eventId]() {
eventId == VclEventId::WindowMouseButtonDown
? pXWindow->mpImpl->getMouseListeners().mousePressed(aEvent)
: pXWindow->mpImpl->getMouseListeners().mouseReleased(aEvent);
};
ImplExecuteAsyncWithoutSolarLock(aCallback);
Callback aCallback = [ this, aEvent ]() // Next window (parent)
{ this->mpImpl->getMouseListeners().mouseReleased( aEvent ); }; pWin = pWin->GetWindow(GetWindowType::RealParent);
ImplExecuteAsyncWithoutSolarLock( aCallback );
} }
} }
break; break;