/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) )
CallEventListeners( VclEventId::WindowLoseFocus );
}
// #82968# mouse and key events will be notified after processing ( in ImplNotifyKeyMouseCommandEventListeners() )! // see also ImplHandleMouseEvent(), ImplHandleKey()
// check for docking window // but do nothing if window is docked and locked
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); if ((GetStyle() & WB_DOCKABLE) &&
pWrapper && ( pWrapper->IsFloatingMode() || !pWrapper->IsLocked() ))
{ constbool bDockingSupportCrippled = !StyleSettings::GetDockingFloatsSupported();
if ( rNEvt.GetType() == NotifyEventType::MOUSEBUTTONDOWN )
{ const MouseEvent* pMEvt = rNEvt.GetMouseEvent(); bool bHit = pWrapper->GetDragArea().Contains( pMEvt->GetPosPixel() ); if ( pMEvt->IsLeft() )
{ if (!bDockingSupportCrippled && pMEvt->IsMod1() && (pMEvt->GetClicks() == 2))
{ // ctrl double click toggles floating mode
pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() ); returntrue;
} elseif ( pMEvt->GetClicks() == 1 && bHit)
{ // allow start docking during mouse move
pWrapper->ImplEnableStartDocking(); returntrue;
}
}
} elseif ( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
{ const MouseEvent* pMEvt = rNEvt.GetMouseEvent(); bool bHit = pWrapper->GetDragArea().Contains( pMEvt->GetPosPixel() ); if ( pMEvt->IsLeft() )
{ // check if a single click initiated this sequence ( ImplStartDockingEnabled() ) // check if window is docked and if( pWrapper->ImplStartDockingEnabled() && !pWrapper->IsFloatingMode() &&
!pWrapper->IsDocking() && bHit )
{
Point aPos = pMEvt->GetPosPixel();
vcl::Window* pWindow = rNEvt.GetWindow(); if ( pWindow != this )
{
aPos = pWindow->OutputToScreenPixel( aPos );
aPos = ScreenToOutputPixel( aPos );
}
pWrapper->ImplStartDocking( aPos );
} returntrue;
}
} elseif( rNEvt.GetType() == NotifyEventType::KEYINPUT )
{ const vcl::KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode(); if (rKey.GetCode() == KEY_F10 && rKey.GetModifier() &&
rKey.IsShift() && rKey.IsMod1() && !bDockingSupportCrippled)
{
pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() ); /* At this point the floating toolbar frame does not have the * input focus since these frames don't get the focus per default * To enable keyboard handling of this toolbar set the input focus * to the frame. This needs to be done with ToTop since GrabFocus * would not notice any change since "this" already has the focus.
*/ if( pWrapper->IsFloatingMode() )
ToTop( ToTopFlags::GrabFocusOnly ); returntrue;
}
}
}
// manage the dialogs if ( (GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL )
{ // if the parent also has dialog control activated, the parent takes over control if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) || (rNEvt.GetType() == NotifyEventType::KEYUP) )
{ // ScGridWindow has WB_DIALOGCONTROL set, so pressing tab in ScCheckListMenuControl won't // get processed here by the toplevel DockingWindow of ScCheckListMenuControl by // just checking if parentNotDialogControl is true bool bTopLevelFloatingWindow = (pWrapper && pWrapper->IsFloatingMode()); if (ImplIsOverlapWindow() || parentNotDialogControl(this) || bTopLevelFloatingWindow)
{
bRet = ImplDlgCtrl( *rNEvt.GetKeyEvent(), rNEvt.GetType() == NotifyEventType::KEYINPUT );
}
} elseif ( (rNEvt.GetType() == NotifyEventType::GETFOCUS) || (rNEvt.GetType() == NotifyEventType::LOSEFOCUS) )
{
ImplDlgCtrlFocusChanged( rNEvt.GetWindow(), rNEvt.GetType() == NotifyEventType::GETFOCUS ); if ( (rNEvt.GetWindow() == this) && (rNEvt.GetType() == NotifyEventType::GETFOCUS) &&
!(GetStyle() & WB_TABSTOP) && !(mpWindowImpl->mnDlgCtrlFlags & DialogControlFlags::WantFocus) )
{
vcl::Window* pFirstChild = ImplGetDlgWindow( 0, GetDlgWindowType::First ); if ( pFirstChild )
pFirstChild->ImplControlFocus();
}
}
}
if ( !bRet )
{ if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() )
bRet = mpWindowImpl->mpParent->CompatNotify( rNEvt );
}
// if we have ObjectDying, then the bIsDisposed flag has already been set, // but we still need to let listeners know. constbool bIgnoreDisposed = nEvent == VclEventId::ObjectDying;
if ( !bIgnoreDisposed && xWindow->isDisposed() ) return;
// If maEventListeners is empty, the XVCLWindow has not yet been initialized. // Calling GetComponentInterface will do that. if (mpWindowImpl->maEventListeners.empty() && pData)
xWindow->GetComponentInterface();
if (!mpWindowImpl->maEventListeners.empty())
{ // Copy the list, because this can be destroyed when calling a Link...
std::vector<Link<VclWindowEvent&,void>> aCopy( mpWindowImpl->maEventListeners ); // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
mpWindowImpl->mnEventListenersIteratingCount++; auto& rWindowImpl = *mpWindowImpl;
comphelper::ScopeGuard aGuard(
[&rWindowImpl, &xWindow, &bIgnoreDisposed]()
{ if (bIgnoreDisposed || !xWindow->isDisposed())
{
rWindowImpl.mnEventListenersIteratingCount--; if (rWindowImpl.mnEventListenersIteratingCount == 0)
rWindowImpl.maEventListenersDeleted.clear();
}
}
); for ( const Link<VclWindowEvent&,void>& rLink : aCopy )
{ if (!bIgnoreDisposed && xWindow->isDisposed()) break; // check this hasn't been removed in some re-enterancy scenario fdo#47368 if( rWindowImpl.maEventListenersDeleted.find(rLink) == rWindowImpl.maEventListenersDeleted.end() )
rLink.Call( aEvent );
}
}
while ( xWindow )
{
if ( !bIgnoreDisposed && xWindow->isDisposed() ) return;
if (!xWindow->mpWindowImpl) break;
auto& rWindowImpl = *xWindow->mpWindowImpl; if (!rWindowImpl.maChildEventListeners.empty())
{ // Copy the list, because this can be destroyed when calling a Link...
std::vector<Link<VclWindowEvent&,void>> aCopy( rWindowImpl.maChildEventListeners ); // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
rWindowImpl.mnChildEventListenersIteratingCount++;
comphelper::ScopeGuard aGuard(
[&rWindowImpl, &xWindow, &bIgnoreDisposed]()
{ if (bIgnoreDisposed || !xWindow->isDisposed())
{
rWindowImpl.mnChildEventListenersIteratingCount--; if (rWindowImpl.mnChildEventListenersIteratingCount == 0)
rWindowImpl.maChildEventListenersDeleted.clear();
}
}
); for ( const Link<VclWindowEvent&,void>& rLink : aCopy )
{ if (!bIgnoreDisposed && xWindow->isDisposed()) return; // Check this hasn't been removed in some re-enterancy scenario fdo#47368. if( rWindowImpl.maChildEventListenersDeleted.find(rLink) == rWindowImpl.maChildEventListenersDeleted.end() )
rLink.Call( aEvent );
}
}
if ( !bIgnoreDisposed && xWindow->isDisposed() ) return;
auto pTmpEvent = pSVEvent.get(); if (!mpWindowImpl->mpFrame->PostEvent( std::move(pSVEvent) )) return nullptr; return pTmpEvent;
}
void Window::RemoveUserEvent( ImplSVEvent * nUserEvent )
{
SAL_WARN_IF( nUserEvent->mpWindow.get() != this, "vcl", "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed" );
SAL_WARN_IF( !nUserEvent->mbCall, "vcl", "Window::RemoveUserEvent(): Event is already removed" );
if ( nUserEvent->mpWindow )
{
nUserEvent->mpWindow = nullptr;
}
nUserEvent->mbCall = false;
}
static MouseEvent ImplTranslateMouseEvent( const MouseEvent& rE, vcl::Window const * pSource, vcl::Window const * pDest )
{ // the mouse event occurred in a different window, we need to translate the coordinates of // the mouse cursor within that (source) window to the coordinates the mouse cursor would // be in the destination window
Point aPos = pSource->OutputToScreenPixel( rE.GetPosPixel() ); return MouseEvent( pDest->ScreenToOutputPixel( aPos ), rE.GetClicks(), rE.GetMode(), rE.GetButtons(), rE.GetModifier() );
}
void Window::ImplNotifyKeyMouseCommandEventListeners( NotifyEvent& rNEvt )
{ if( rNEvt.GetType() == NotifyEventType::COMMAND )
{ const CommandEvent* pCEvt = rNEvt.GetCommandEvent(); if ( pCEvt->GetCommand() != CommandEventId::ContextMenu ) // non context menu events are not to be notified up the chain // so we return immediately return;
if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
{ // not interested: The event listeners are already called in ::Command, // and calling them here a second time doesn't make sense if ( rNEvt.GetWindow() != this )
{
CommandEvent aCommandEvent;
if ( !pCEvt->IsMouseEvent() )
{
aCommandEvent = *pCEvt;
} else
{ // the mouse event occurred in a different window, we need to translate the coordinates of // the mouse cursor within that window to the coordinates the mouse cursor would be in the // current window
vcl::Window* pSource = rNEvt.GetWindow();
Point aPos = pSource->OutputToScreenPixel( pCEvt->GetMousePosPixel() );
aCommandEvent = CommandEvent( ScreenToOutputPixel( aPos ), pCEvt->GetCommand(), pCEvt->IsMouseEvent(), pCEvt->GetEventData() );
}
// #82968# notify event listeners for mouse and key events separately and // not in PreNotify ( as for focus listeners ) // this allows for processing those events internally first and pass it to // the toolkit later
VclPtr<vcl::Window> xWindow = this;
if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
{ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
{ if ( rNEvt.GetWindow() == this )
CallEventListeners( VclEventId::WindowMouseMove, const_cast<MouseEvent *>(rNEvt.GetMouseEvent()) ); else
{
MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
CallEventListeners( VclEventId::WindowMouseMove, &aMouseEvent );
}
}
} elseif( rNEvt.GetType() == NotifyEventType::MOUSEBUTTONUP )
{ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
{ if ( rNEvt.GetWindow() == this )
CallEventListeners( VclEventId::WindowMouseButtonUp, const_cast<MouseEvent *>(rNEvt.GetMouseEvent()) ); else
{
MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
CallEventListeners( VclEventId::WindowMouseButtonUp, &aMouseEvent );
}
}
} elseif( rNEvt.GetType() == NotifyEventType::MOUSEBUTTONDOWN )
{ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
{ if ( rNEvt.GetWindow() == this )
CallEventListeners( VclEventId::WindowMouseButtonDown, const_cast<MouseEvent *>(rNEvt.GetMouseEvent()) ); else
{
MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this );
CallEventListeners( VclEventId::WindowMouseButtonDown, &aMouseEvent );
}
}
} elseif( rNEvt.GetType() == NotifyEventType::KEYINPUT )
{ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
CallEventListeners( VclEventId::WindowKeyInput, const_cast<KeyEvent *>(rNEvt.GetKeyEvent()) );
} elseif( rNEvt.GetType() == NotifyEventType::KEYUP )
{ if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) )
CallEventListeners( VclEventId::WindowKeyUp, const_cast<KeyEvent *>(rNEvt.GetKeyEvent()) );
}
if ( xWindow->isDisposed() ) return;
// #106721# check if we're part of a compound control and notify
vcl::Window *pParent = ImplGetParent(); while( pParent )
{ if( pParent->IsCompoundControl() )
{
pParent->ImplNotifyKeyMouseCommandEventListeners( rNEvt ); break;
}
pParent = pParent->ImplGetParent();
}
}
// Normally we avoid blanking on re-size unless people might notice: if( GetBackground().IsGradient() )
Invalidate();
Resize();
// #88419# Most classes don't call the base class in Resize() and Move(), // => Call ImpleResize/Move instead of Resize/Move directly...
CallEventListeners( VclEventId::WindowResize );
}
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
mpWindowImpl->maPos = Point(g.x(), g.y()); if( pParentFrame )
{
g = pParentFrame->GetGeometry();
mpWindowImpl->maPos -= Point(g.x(), g.y());
} // the client window and all its subclients have the same position as the borderframe // this is important for floating toolbars where the borderwindow is a floating window // which has another borderwindow (ie the system floating window)
vcl::Window *pClientWin = mpWindowImpl->mpClientWindow; while( pClientWin )
{
pClientWin->mpWindowImpl->maPos = mpWindowImpl->maPos;
pClientWin = pClientWin->mpWindowImpl->mpClientWindow;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.