summaryrefslogtreecommitdiffstats
path: root/vcl/source/window/stacking.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/source/window/stacking.cxx1151
1 files changed, 1151 insertions, 0 deletions
diff --git a/vcl/source/window/stacking.cxx b/vcl/source/window/stacking.cxx
new file mode 100644
index 000000000..928c456ee
--- /dev/null
+++ b/vcl/source/window/stacking.cxx
@@ -0,0 +1,1151 @@
+/* -*- 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 .
+ */
+
+#include <vcl/syswin.hxx>
+#include <vcl/window.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <sal/log.hxx>
+
+#include <salframe.hxx>
+#include <salobj.hxx>
+#include <svdata.hxx>
+#include <window.h>
+#include <brdwin.hxx>
+
+#include <com/sun/star/awt/XTopWindow.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace ::com::sun::star;
+
+using ::com::sun::star::awt::XTopWindow;
+
+struct ImplCalcToTopData
+{
+ std::unique_ptr<ImplCalcToTopData> mpNext;
+ VclPtr<vcl::Window> mpWindow;
+ std::unique_ptr<vcl::Region> mpInvalidateRegion;
+};
+
+namespace vcl {
+
+vcl::Window* Window::ImplGetTopmostFrameWindow()
+{
+ vcl::Window *pTopmostParent = this;
+ while( pTopmostParent->ImplGetParent() )
+ pTopmostParent = pTopmostParent->ImplGetParent();
+ return pTopmostParent->mpWindowImpl->mpFrameWindow;
+}
+
+void Window::ImplInsertWindow( vcl::Window* pParent )
+{
+ mpWindowImpl->mpParent = pParent;
+ mpWindowImpl->mpRealParent = pParent;
+
+ if ( !pParent || mpWindowImpl->mbFrame )
+ return;
+
+ // search frame window and set window frame data
+ vcl::Window* pFrameParent = pParent->mpWindowImpl->mpFrameWindow;
+ mpWindowImpl->mpFrameData = pFrameParent->mpWindowImpl->mpFrameData;
+ if (mpWindowImpl->mpFrame != pFrameParent->mpWindowImpl->mpFrame)
+ {
+ mpWindowImpl->mpFrame = pFrameParent->mpWindowImpl->mpFrame;
+ if (mpWindowImpl->mpSysObj)
+ mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
+ }
+ mpWindowImpl->mpFrameWindow = pFrameParent;
+ mpWindowImpl->mbFrame = false;
+
+ // search overlap window and insert window in list
+ if ( ImplIsOverlapWindow() )
+ {
+ vcl::Window* pFirstOverlapParent = pParent;
+ while ( !pFirstOverlapParent->ImplIsOverlapWindow() )
+ pFirstOverlapParent = pFirstOverlapParent->ImplGetParent();
+ mpWindowImpl->mpOverlapWindow = pFirstOverlapParent;
+
+ mpWindowImpl->mpNextOverlap = mpWindowImpl->mpFrameData->mpFirstOverlap;
+ mpWindowImpl->mpFrameData->mpFirstOverlap = this;
+
+ // Overlap-Windows are by default the uppermost
+ mpWindowImpl->mpNext = pFirstOverlapParent->mpWindowImpl->mpFirstOverlap;
+ pFirstOverlapParent->mpWindowImpl->mpFirstOverlap = this;
+ if ( !pFirstOverlapParent->mpWindowImpl->mpLastOverlap )
+ pFirstOverlapParent->mpWindowImpl->mpLastOverlap = this;
+ else
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
+ }
+ else
+ {
+ if ( pParent->ImplIsOverlapWindow() )
+ mpWindowImpl->mpOverlapWindow = pParent;
+ else
+ mpWindowImpl->mpOverlapWindow = pParent->mpWindowImpl->mpOverlapWindow;
+ mpWindowImpl->mpPrev = pParent->mpWindowImpl->mpLastChild;
+ pParent->mpWindowImpl->mpLastChild = this;
+ if ( !pParent->mpWindowImpl->mpFirstChild )
+ pParent->mpWindowImpl->mpFirstChild = this;
+ else
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ }
+}
+
+void Window::ImplRemoveWindow( bool bRemoveFrameData )
+{
+ // remove window from the lists
+ if ( !mpWindowImpl->mbFrame )
+ {
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpFrameData->mpFirstOverlap.get() == this )
+ mpWindowImpl->mpFrameData->mpFirstOverlap = mpWindowImpl->mpNextOverlap;
+ else
+ {
+ vcl::Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap;
+ while ( pTempWin->mpWindowImpl->mpNextOverlap.get() != this )
+ pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
+ pTempWin->mpWindowImpl->mpNextOverlap = mpWindowImpl->mpNextOverlap;
+ }
+
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+ }
+ else
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else if ( mpWindowImpl->mpParent )
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else if ( mpWindowImpl->mpParent )
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
+ }
+
+ mpWindowImpl->mpPrev = nullptr;
+ mpWindowImpl->mpNext = nullptr;
+ }
+
+ if ( bRemoveFrameData )
+ {
+ // release the graphic
+ OutputDevice *pOutDev = GetOutDev();
+ pOutDev->ReleaseGraphics();
+ }
+}
+
+void Window::reorderWithinParent(sal_uInt16 nNewPosition)
+{
+ sal_uInt16 nChildCount = 0;
+ vcl::Window *pSource = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
+ while (pSource)
+ {
+ if (nChildCount == nNewPosition)
+ break;
+ pSource = pSource->mpWindowImpl->mpNext;
+ nChildCount++;
+ }
+
+ if (pSource == this) //already at the right place
+ return;
+
+ ImplRemoveWindow(false);
+
+ if (pSource)
+ {
+ mpWindowImpl->mpNext = pSource;
+ mpWindowImpl->mpPrev = pSource->mpWindowImpl->mpPrev;
+ pSource->mpWindowImpl->mpPrev = this;
+ }
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
+
+ if (mpWindowImpl->mpPrev)
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
+}
+
+void Window::ImplToBottomChild()
+{
+ if ( ImplIsOverlapWindow() || mpWindowImpl->mbReallyVisible || (mpWindowImpl->mpParent->mpWindowImpl->mpLastChild.get() == this) )
+ return;
+
+ // put the window to the end of the list
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ mpWindowImpl->mpPrev = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ mpWindowImpl->mpNext = nullptr;
+}
+
+void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData )
+{
+ SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplCalcToTop(): Is not an OverlapWindow" );
+
+ if ( mpWindowImpl->mbFrame )
+ return;
+
+ if ( !IsReallyVisible() )
+ return;
+
+ // calculate region, where the window overlaps with other windows
+ vcl::Region aRegion( GetOutputRectPixel() );
+ vcl::Region aInvalidateRegion;
+ ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion );
+
+ if ( !aInvalidateRegion.IsEmpty() )
+ {
+ ImplCalcToTopData* pData = new ImplCalcToTopData;
+ pPrevData->mpNext.reset(pData);
+ pData->mpWindow = this;
+ pData->mpInvalidateRegion.reset(new vcl::Region( aInvalidateRegion ));
+ }
+}
+
+void Window::ImplToTop( ToTopFlags nFlags )
+{
+ SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplToTop(): Is not an OverlapWindow" );
+
+ if ( mpWindowImpl->mbFrame )
+ {
+ // on a mouse click in the external window, it is the latter's
+ // responsibility to assure our frame is put in front
+ if ( !mpWindowImpl->mpFrameData->mbHasFocus &&
+ !mpWindowImpl->mpFrameData->mbSysObjFocus &&
+ !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl &&
+ !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl )
+ {
+ // do not bring floating windows on the client to top
+ if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) )
+ {
+ SalFrameToTop nSysFlags = SalFrameToTop::NONE;
+ if ( nFlags & ToTopFlags::RestoreWhenMin )
+ nSysFlags |= SalFrameToTop::RestoreWhenMin;
+ if ( nFlags & ToTopFlags::ForegroundTask )
+ nSysFlags |= SalFrameToTop::ForegroundTask;
+ if ( nFlags & ToTopFlags::GrabFocusOnly )
+ nSysFlags |= SalFrameToTop::GrabFocusOnly;
+ mpWindowImpl->mpFrame->ToTop( nSysFlags );
+ }
+ }
+ }
+ else
+ {
+ if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap.get() != this )
+ {
+ // remove window from the list
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+
+ // take AlwaysOnTop into account
+ bool bOnTop = IsAlwaysOnTopEnabled();
+ vcl::Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ if ( !bOnTop )
+ {
+ while ( pNextWin )
+ {
+ if ( !pNextWin->IsAlwaysOnTopEnabled() )
+ break;
+ pNextWin = pNextWin->mpWindowImpl->mpNext;
+ }
+ }
+
+ // add the window to the list again
+ mpWindowImpl->mpNext = pNextWin;
+ if ( pNextWin )
+ {
+ mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev;
+ pNextWin->mpWindowImpl->mpPrev = this;
+ }
+ else
+ {
+ mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
+ }
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
+
+ // recalculate ClipRegion of this and all overlapping windows
+ if ( IsReallyVisible() )
+ {
+ mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows();
+ }
+ }
+ }
+}
+
+void Window::ImplStartToTop( ToTopFlags nFlags )
+{
+ ImplCalcToTopData aStartData;
+ ImplCalcToTopData* pCurData;
+ vcl::Window* pOverlapWindow;
+ if ( ImplIsOverlapWindow() )
+ pOverlapWindow = this;
+ else
+ pOverlapWindow = mpWindowImpl->mpOverlapWindow;
+
+ // first calculate paint areas
+ vcl::Window* pTempOverlapWindow = pOverlapWindow;
+ aStartData.mpNext = nullptr;
+ pCurData = &aStartData;
+ do
+ {
+ pTempOverlapWindow->ImplCalcToTop( pCurData );
+ if ( pCurData->mpNext )
+ pCurData = pCurData->mpNext.get();
+ pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
+ // next calculate the paint areas of the ChildOverlap windows
+ pTempOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pTempOverlapWindow )
+ {
+ pTempOverlapWindow->ImplCalcToTop( pCurData );
+ if ( pCurData->mpNext )
+ pCurData = pCurData->mpNext.get();
+ pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext;
+ }
+
+ // and next change the windows list
+ pTempOverlapWindow = pOverlapWindow;
+ do
+ {
+ pTempOverlapWindow->ImplToTop( nFlags );
+ pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
+ }
+ while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
+ // as last step invalidate the invalid areas
+ pCurData = aStartData.mpNext.get();
+ while ( pCurData )
+ {
+ pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion.get(), InvalidateFlags::Children );
+ pCurData = pCurData->mpNext.get();
+ }
+}
+
+void Window::ImplFocusToTop( ToTopFlags nFlags, bool bReallyVisible )
+{
+ // do we need to fetch the focus?
+ if ( !(nFlags & ToTopFlags::NoGrabFocus) )
+ {
+ // first window with GrabFocus-Activate gets the focus
+ vcl::Window* pFocusWindow = this;
+ while ( !pFocusWindow->ImplIsOverlapWindow() )
+ {
+ // if the window has no BorderWindow, we
+ // should always find the belonging BorderWindow
+ if ( !pFocusWindow->mpWindowImpl->mpBorderWindow )
+ {
+ if ( pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus )
+ break;
+ }
+ pFocusWindow = pFocusWindow->ImplGetParent();
+ }
+ if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus) &&
+ !pFocusWindow->HasChildPathFocus( true ) )
+ pFocusWindow->GrabFocus();
+ }
+
+ if ( bReallyVisible )
+ ImplGenerateMouseMove();
+}
+
+void Window::ImplShowAllOverlaps()
+{
+ vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible )
+ {
+ pOverlapWindow->Show( true, ShowFlags::NoActivate );
+ pOverlapWindow->mpWindowImpl->mbOverlapVisible = false;
+ }
+
+ pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ }
+}
+
+void Window::ImplHideAllOverlaps()
+{
+ vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ if ( pOverlapWindow->IsVisible() )
+ {
+ pOverlapWindow->mpWindowImpl->mbOverlapVisible = true;
+ pOverlapWindow->Show( false );
+ }
+
+ pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ }
+}
+
+void Window::ToTop( ToTopFlags nFlags )
+{
+ if (!mpWindowImpl)
+ return;
+
+ ImplStartToTop( nFlags );
+ ImplFocusToTop( nFlags, IsReallyVisible() );
+}
+
+void Window::SetZOrder( vcl::Window* pRefWindow, ZOrderFlags nFlags )
+{
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags );
+ return;
+ }
+
+ if ( nFlags & ZOrderFlags::First )
+ {
+ if ( ImplIsOverlapWindow() )
+ pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ else
+ pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
+ nFlags |= ZOrderFlags::Before;
+ }
+ else if ( nFlags & ZOrderFlags::Last )
+ {
+ if ( ImplIsOverlapWindow() )
+ pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
+ else
+ pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
+ nFlags |= ZOrderFlags::Behind;
+ }
+
+ while ( pRefWindow && pRefWindow->mpWindowImpl->mpBorderWindow )
+ pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow;
+ if (!pRefWindow || pRefWindow == this || mpWindowImpl->mbFrame)
+ return;
+
+ SAL_WARN_IF( pRefWindow->mpWindowImpl->mpParent != mpWindowImpl->mpParent, "vcl", "Window::SetZOrder() - pRefWindow has other parent" );
+ if ( nFlags & ZOrderFlags::Before )
+ {
+ if ( pRefWindow->mpWindowImpl->mpPrev.get() == this )
+ return;
+
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpPrev )
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
+ }
+ else
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpPrev )
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
+ }
+
+ mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev;
+ mpWindowImpl->mpNext = pRefWindow;
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
+ }
+ else if ( nFlags & ZOrderFlags::Behind )
+ {
+ if ( pRefWindow->mpWindowImpl->mpNext.get() == this )
+ return;
+
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpNext )
+ mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
+ }
+ else
+ {
+ if ( mpWindowImpl->mpPrev )
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
+ else
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
+ if ( !pRefWindow->mpWindowImpl->mpNext )
+ mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
+ }
+
+ mpWindowImpl->mpPrev = pRefWindow;
+ mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext;
+ if ( mpWindowImpl->mpNext )
+ mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
+ mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
+ }
+
+ if ( !IsReallyVisible() )
+ return;
+
+ if ( !mpWindowImpl->mbInitWinClipRegion && mpWindowImpl->maWinClipRegion.IsEmpty() )
+ return;
+
+ bool bInitWinClipRegion = mpWindowImpl->mbInitWinClipRegion;
+ ImplSetClipFlag();
+
+ // When ClipRegion was not initialised, assume
+ // the window has not been sent, therefore do not
+ // trigger any Invalidates. This is an optimization
+ // for HTML documents with many controls. If this
+ // check gives problems, a flag should be introduced
+ // which tracks whether the window has already been
+ // emitted after Show
+ if ( bInitWinClipRegion )
+ return;
+
+ // Invalidate all windows which are next to each other
+ // Is INCOMPLETE !!!
+ tools::Rectangle aWinRect = GetOutputRectPixel();
+ vcl::Window* pWindow = nullptr;
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( mpWindowImpl->mpOverlapWindow )
+ pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ }
+ else
+ pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
+ // Invalidate all windows in front of us and which are covered by us
+ while ( pWindow )
+ {
+ if ( pWindow == this )
+ break;
+ tools::Rectangle aCompRect = pWindow->GetOutputRectPixel();
+ if ( aWinRect.Overlaps( aCompRect ) )
+ pWindow->Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ // If we are covered by a window in the background
+ // we should redraw it
+ while ( pWindow )
+ {
+ if ( pWindow != this )
+ {
+ tools::Rectangle aCompRect = pWindow->GetOutputRectPixel();
+ if ( aWinRect.Overlaps( aCompRect ) )
+ {
+ Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
+ break;
+ }
+ }
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+void Window::EnableAlwaysOnTop( bool bEnable )
+{
+
+ mpWindowImpl->mbAlwaysOnTop = bEnable;
+
+ if ( mpWindowImpl->mpBorderWindow )
+ mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable );
+ else if ( bEnable && IsReallyVisible() )
+ ToTop();
+
+ if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable );
+}
+
+bool Window::IsTopWindow() const
+{
+ if ( !mpWindowImpl || mpWindowImpl->mbInDispose )
+ return false;
+
+ // topwindows must be frames or they must have a borderwindow which is a frame
+ if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) )
+ return false;
+
+ ImplGetWinData();
+ if( mpWindowImpl->mpWinData->mnIsTopWindow == sal_uInt16(~0)) // still uninitialized
+ {
+ // #113722#, cache result of expensive queryInterface call
+ vcl::Window *pThisWin = const_cast<vcl::Window*>(this);
+ uno::Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY );
+ pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0;
+ }
+ return mpWindowImpl->mpWinData->mnIsTopWindow == 1;
+}
+
+vcl::Window* Window::ImplFindWindow( const Point& rFramePos )
+{
+ vcl::Window* pTempWindow;
+ vcl::Window* pFindWindow;
+
+ // first check all overlapping windows
+ pTempWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pTempWindow )
+ {
+ pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
+ if ( pFindWindow )
+ return pFindWindow;
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+
+ // then we check our window
+ if ( !mpWindowImpl->mbVisible )
+ return nullptr;
+
+ WindowHitTest nHitTest = ImplHitTest( rFramePos );
+ if ( nHitTest & WindowHitTest::Inside )
+ {
+ // and then we check all child windows
+ pTempWindow = mpWindowImpl->mpFirstChild;
+ while ( pTempWindow )
+ {
+ pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
+ if ( pFindWindow )
+ return pFindWindow;
+ pTempWindow = pTempWindow->mpWindowImpl->mpNext;
+ }
+
+ if ( nHitTest & WindowHitTest::Transparent )
+ return nullptr;
+ else
+ return this;
+ }
+
+ return nullptr;
+}
+
+bool Window::ImplIsRealParentPath( const vcl::Window* pWindow ) const
+{
+ pWindow = pWindow->GetParent();
+ while ( pWindow )
+ {
+ if ( pWindow == this )
+ return true;
+ pWindow = pWindow->GetParent();
+ }
+
+ return false;
+}
+
+bool Window::ImplIsChild( const vcl::Window* pWindow, bool bSystemWindow ) const
+{
+ do
+ {
+ if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
+ break;
+
+ pWindow = pWindow->ImplGetParent();
+
+ if ( pWindow == this )
+ return true;
+ }
+ while ( pWindow );
+
+ return false;
+}
+
+bool Window::ImplIsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
+{
+ if ( this == pWindow )
+ return true;
+ return ImplIsChild( pWindow, bSystemWindow );
+}
+
+void Window::ImplResetReallyVisible()
+{
+ bool bBecameReallyInvisible = mpWindowImpl->mbReallyVisible;
+
+ GetOutDev()->mbDevOutput = false;
+ mpWindowImpl->mbReallyVisible = false;
+ mpWindowImpl->mbReallyShown = false;
+
+ // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
+ // For this, the data member of the event must not be NULL.
+ // Previously, we did this in Window::Show, but there some events got lost in certain situations.
+ if( bBecameReallyInvisible && ImplIsAccessibleCandidate() )
+ CallEventListeners( VclEventId::WindowHide, this );
+ // TODO. It's kind of a hack that we're re-using the VclEventId::WindowHide. Normally, we should
+ // introduce another event which explicitly triggers the Accessibility implementations.
+
+ vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ pWindow->ImplResetReallyVisible();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+
+ pWindow = mpWindowImpl->mpFirstChild;
+ while ( pWindow )
+ {
+ if ( pWindow->mpWindowImpl->mbReallyVisible )
+ pWindow->ImplResetReallyVisible();
+ pWindow = pWindow->mpWindowImpl->mpNext;
+ }
+}
+
+void Window::ImplUpdateWindowPtr( vcl::Window* pWindow )
+{
+ if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
+ {
+ // release graphic
+ OutputDevice *pOutDev = GetOutDev();
+ pOutDev->ReleaseGraphics();
+ }
+
+ mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData;
+ if (mpWindowImpl->mpFrame != pWindow->mpWindowImpl->mpFrame)
+ {
+ mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame;
+ if (mpWindowImpl->mpSysObj)
+ mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
+ }
+ mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow;
+ if ( pWindow->ImplIsOverlapWindow() )
+ mpWindowImpl->mpOverlapWindow = pWindow;
+ else
+ mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow;
+
+ vcl::Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplUpdateWindowPtr( pWindow );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+void Window::ImplUpdateWindowPtr()
+{
+ vcl::Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ pChild->ImplUpdateWindowPtr( this );
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+}
+
+void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame )
+{
+ bool bVisible = IsVisible();
+ Show( false );
+ ImplRemoveWindow( bNewFrame );
+ vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
+ ImplInsertWindow( ImplGetParent() );
+ mpWindowImpl->mpRealParent = pRealParent;
+ ImplUpdateWindowPtr();
+ if ( ImplUpdatePos() )
+ ImplUpdateSysObjPos();
+
+ if ( bNewFrame )
+ {
+ vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
+ pOverlapWindow = pNextOverlapWindow;
+ }
+ }
+
+ if ( bVisible )
+ Show();
+}
+
+SystemWindow* Window::GetSystemWindow() const
+{
+
+ const vcl::Window* pWin = this;
+ while ( pWin && !pWin->IsSystemWindow() )
+ pWin = pWin->GetParent();
+ return static_cast<SystemWindow*>(const_cast<Window*>(pWin));
+}
+
+static SystemWindow *ImplGetLastSystemWindow( vcl::Window *pWin )
+{
+ // get the most top-level system window, the one that contains the taskpanelist
+ SystemWindow *pSysWin = nullptr;
+ if( !pWin )
+ return pSysWin;
+ vcl::Window *pMyParent = pWin;
+ while ( pMyParent )
+ {
+ if ( pMyParent->IsSystemWindow() )
+ pSysWin = static_cast<SystemWindow*>(pMyParent);
+ pMyParent = pMyParent->GetParent();
+ }
+ return pSysWin;
+}
+
+void Window::SetParent( vcl::Window* pNewParent )
+{
+ SAL_WARN_IF( !pNewParent, "vcl", "Window::SetParent(): pParent == NULL" );
+ SAL_WARN_IF( pNewParent == this, "vcl", "someone tried to reparent a window to itself" );
+
+ if( !pNewParent || pNewParent == this )
+ return;
+
+ // check if the taskpanelist would change and move the window pointer accordingly
+ SystemWindow *pSysWin = ImplGetLastSystemWindow(this);
+ SystemWindow *pNewSysWin = nullptr;
+ bool bChangeTaskPaneList = false;
+ if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) )
+ {
+ pNewSysWin = ImplGetLastSystemWindow( pNewParent );
+ if( pNewSysWin && pNewSysWin != pSysWin )
+ {
+ bChangeTaskPaneList = true;
+ pSysWin->GetTaskPaneList()->RemoveWindow( this );
+ }
+ }
+ // remove ownerdraw decorated windows from list in the top-most frame window
+ if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
+ {
+ ::std::vector< VclPtr<vcl::Window> >& rList = ImplGetOwnerDrawList();
+ auto p = ::std::find( rList.begin(), rList.end(), VclPtr<vcl::Window>(this) );
+ if( p != rList.end() )
+ rList.erase( p );
+ }
+
+ ImplSetFrameParent( pNewParent );
+
+ if ( mpWindowImpl->mpBorderWindow )
+ {
+ mpWindowImpl->mpRealParent = pNewParent;
+ mpWindowImpl->mpBorderWindow->SetParent( pNewParent );
+ return;
+ }
+
+ if ( mpWindowImpl->mpParent.get() == pNewParent )
+ return;
+
+ if ( mpWindowImpl->mbFrame )
+ mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame );
+
+ bool bVisible = IsVisible();
+ Show( false, ShowFlags::NoFocusChange );
+
+ // check if the overlap window changes
+ vcl::Window* pOldOverlapWindow;
+ vcl::Window* pNewOverlapWindow = nullptr;
+ if ( ImplIsOverlapWindow() )
+ pOldOverlapWindow = nullptr;
+ else
+ {
+ pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow();
+ if ( mpWindowImpl->mpOverlapWindow.get() != pNewOverlapWindow )
+ pOldOverlapWindow = mpWindowImpl->mpOverlapWindow;
+ else
+ pOldOverlapWindow = nullptr;
+ }
+
+ // convert windows in the hierarchy
+ bool bFocusOverlapWin = HasChildPathFocus( true );
+ bool bFocusWin = HasChildPathFocus();
+ bool bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow;
+ if ( bNewFrame )
+ {
+ if ( mpWindowImpl->mpFrameData->mpFocusWin )
+ {
+ if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) )
+ mpWindowImpl->mpFrameData->mpFocusWin = nullptr;
+ }
+ if ( mpWindowImpl->mpFrameData->mpMouseMoveWin )
+ {
+ if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) )
+ mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr;
+ }
+ if ( mpWindowImpl->mpFrameData->mpMouseDownWin )
+ {
+ if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) )
+ mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr;
+ }
+ }
+ ImplRemoveWindow( bNewFrame );
+ ImplInsertWindow( pNewParent );
+ if ( mpWindowImpl->mnParentClipMode & ParentClipMode::Clip )
+ pNewParent->mpWindowImpl->mbClipChildren = true;
+ ImplUpdateWindowPtr();
+ if ( ImplUpdatePos() )
+ ImplUpdateSysObjPos();
+
+ // If the Overlap-Window has changed, we need to test whether
+ // OverlapWindows that had the Child window as their parent
+ // need to be put into the window hierarchy.
+ if ( ImplIsOverlapWindow() )
+ {
+ if ( bNewFrame )
+ {
+ vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
+ pOverlapWindow = pNextOverlapWindow;
+ }
+ }
+ }
+ else if ( pOldOverlapWindow )
+ {
+ // reset Focus-Save
+ if ( bFocusWin ||
+ (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow &&
+ IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) )
+ pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
+
+ vcl::Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap;
+ while ( pOverlapWindow )
+ {
+ vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
+ if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) )
+ pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
+ pOverlapWindow = pNextOverlapWindow;
+ }
+
+ // update activate-status at next overlap window
+ if ( HasChildPathFocus( true ) )
+ ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
+ }
+
+ // also convert Activate-Status
+ if ( bNewFrame )
+ {
+ if ( (GetType() == WindowType::BORDERWINDOW) &&
+ (ImplGetWindow()->GetType() == WindowType::FLOATINGWINDOW) )
+ static_cast<ImplBorderWindow*>(this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus );
+ }
+
+ // when required give focus to new frame if
+ // FocusWindow is changed with SetParent()
+ if ( bFocusOverlapWin )
+ {
+ mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow();
+ if ( !mpWindowImpl->mpFrameData->mbHasFocus )
+ {
+ mpWindowImpl->mpFrame->ToTop( SalFrameToTop::NONE );
+ }
+ }
+
+ // Assure DragSource and DropTarget members are created
+ if ( bNewFrame )
+ {
+ GetDropTarget();
+ }
+
+ if( bChangeTaskPaneList )
+ pNewSysWin->GetTaskPaneList()->AddWindow( this );
+
+ if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
+ ImplGetOwnerDrawList().emplace_back(this );
+
+ if ( bVisible )
+ Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
+}
+
+bool Window::IsAncestorOf( const vcl::Window& rWindow ) const
+{
+ return ImplIsRealParentPath(&rWindow);
+}
+
+sal_uInt16 Window::GetChildCount() const
+{
+ if (!mpWindowImpl)
+ return 0;
+
+ sal_uInt16 nChildCount = 0;
+ vcl::Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ nChildCount++;
+ pChild = pChild->mpWindowImpl->mpNext;
+ }
+
+ return nChildCount;
+}
+
+vcl::Window* Window::GetChild( sal_uInt16 nChild ) const
+{
+ if (!mpWindowImpl)
+ return nullptr;
+
+ sal_uInt16 nChildCount = 0;
+ vcl::Window* pChild = mpWindowImpl->mpFirstChild;
+ while ( pChild )
+ {
+ if ( nChild == nChildCount )
+ return pChild;
+ pChild = pChild->mpWindowImpl->mpNext;
+ nChildCount++;
+ }
+
+ return nullptr;
+}
+
+vcl::Window* Window::GetWindow( GetWindowType nType ) const
+{
+ if (!mpWindowImpl)
+ return nullptr;
+
+ switch ( nType )
+ {
+ case GetWindowType::Parent:
+ return mpWindowImpl->mpRealParent;
+
+ case GetWindowType::FirstChild:
+ return mpWindowImpl->mpFirstChild;
+
+ case GetWindowType::LastChild:
+ return mpWindowImpl->mpLastChild;
+
+ case GetWindowType::Prev:
+ return mpWindowImpl->mpPrev;
+
+ case GetWindowType::Next:
+ return mpWindowImpl->mpNext;
+
+ case GetWindowType::FirstOverlap:
+ return mpWindowImpl->mpFirstOverlap;
+
+ case GetWindowType::Overlap:
+ if ( ImplIsOverlapWindow() )
+ return const_cast<vcl::Window*>(this);
+ else
+ return mpWindowImpl->mpOverlapWindow;
+
+ case GetWindowType::ParentOverlap:
+ if ( ImplIsOverlapWindow() )
+ return mpWindowImpl->mpOverlapWindow;
+ else
+ return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow;
+
+ case GetWindowType::Client:
+ return this->ImplGetWindow();
+
+ case GetWindowType::RealParent:
+ return ImplGetParent();
+
+ case GetWindowType::Frame:
+ return mpWindowImpl->mpFrameWindow;
+
+ case GetWindowType::Border:
+ if ( mpWindowImpl->mpBorderWindow )
+ return mpWindowImpl->mpBorderWindow->GetWindow( GetWindowType::Border );
+ return const_cast<vcl::Window*>(this);
+
+ case GetWindowType::FirstTopWindowChild:
+ return ImplGetWinData()->maTopWindowChildren.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren.begin()).get();
+
+ case GetWindowType::NextTopWindowSibling:
+ {
+ if ( !mpWindowImpl->mpRealParent )
+ return nullptr;
+ const ::std::list< VclPtr<vcl::Window> >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
+ ::std::list< VclPtr<vcl::Window> >::const_iterator myPos =
+ ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
+ if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) )
+ return nullptr;
+ return *myPos;
+ }
+
+ }
+
+ return nullptr;
+}
+
+bool Window::IsChild( const vcl::Window* pWindow ) const
+{
+ do
+ {
+ if ( pWindow->ImplIsOverlapWindow() )
+ break;
+
+ pWindow = pWindow->ImplGetParent();
+
+ if ( pWindow == this )
+ return true;
+ }
+ while ( pWindow );
+
+ return false;
+}
+
+bool Window::IsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
+{
+
+ if ( this == pWindow )
+ return true;
+ return ImplIsChild( pWindow, bSystemWindow );
+}
+
+void Window::ImplSetFrameParent( const vcl::Window* pParent )
+{
+ vcl::Window* pFrameWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
+ while( pFrameWindow )
+ {
+ // search all frames that are children of this window
+ // and reparent them
+ if( ImplIsRealParentPath( pFrameWindow ) )
+ {
+ SAL_WARN_IF( mpWindowImpl->mpFrame == pFrameWindow->mpWindowImpl->mpFrame, "vcl", "SetFrameParent to own" );
+ SAL_WARN_IF( !mpWindowImpl->mpFrame, "vcl", "no frame" );
+ SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : nullptr;
+ pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame );
+ }
+ pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame;
+ }
+}
+
+} /* namespace vcl */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */