Update git submodules
[LibreOffice.git] / vcl / source / window / stacking.cxx
blob5ce78f69b426b25e87a5fb2873c7b1bee62d947d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/syswin.hxx>
21 #include <vcl/window.hxx>
22 #include <vcl/taskpanelist.hxx>
23 #include <sal/log.hxx>
25 #include <salframe.hxx>
26 #include <salobj.hxx>
27 #include <svdata.hxx>
28 #include <window.h>
29 #include <brdwin.hxx>
31 #include <com/sun/star/awt/XTopWindow.hpp>
32 #include <com/sun/star/awt/XVclWindowPeer.hpp>
34 using namespace ::com::sun::star::uno;
35 using namespace ::com::sun::star::datatransfer::clipboard;
36 using namespace ::com::sun::star::datatransfer::dnd;
37 using namespace ::com::sun::star;
39 using ::com::sun::star::awt::XTopWindow;
41 struct ImplCalcToTopData
43 std::unique_ptr<ImplCalcToTopData> mpNext;
44 VclPtr<vcl::Window> mpWindow;
45 std::unique_ptr<vcl::Region> mpInvalidateRegion;
48 namespace vcl {
50 vcl::Window* Window::ImplGetTopmostFrameWindow() const
52 const vcl::Window *pTopmostParent = this;
53 while( pTopmostParent->ImplGetParent() )
54 pTopmostParent = pTopmostParent->ImplGetParent();
55 return pTopmostParent->mpWindowImpl->mpFrameWindow;
58 void Window::ImplInsertWindow( vcl::Window* pParent )
60 mpWindowImpl->mpParent = pParent;
61 mpWindowImpl->mpRealParent = pParent;
63 if ( !pParent || mpWindowImpl->mbFrame )
64 return;
66 // search frame window and set window frame data
67 vcl::Window* pFrameParent = pParent->mpWindowImpl->mpFrameWindow;
68 mpWindowImpl->mpFrameData = pFrameParent->mpWindowImpl->mpFrameData;
69 if (mpWindowImpl->mpFrame != pFrameParent->mpWindowImpl->mpFrame)
71 mpWindowImpl->mpFrame = pFrameParent->mpWindowImpl->mpFrame;
72 if (mpWindowImpl->mpSysObj)
73 mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
75 mpWindowImpl->mpFrameWindow = pFrameParent;
76 mpWindowImpl->mbFrame = false;
78 // search overlap window and insert window in list
79 if ( ImplIsOverlapWindow() )
81 vcl::Window* pFirstOverlapParent = pParent;
82 while ( !pFirstOverlapParent->ImplIsOverlapWindow() )
83 pFirstOverlapParent = pFirstOverlapParent->ImplGetParent();
84 mpWindowImpl->mpOverlapWindow = pFirstOverlapParent;
86 mpWindowImpl->mpNextOverlap = mpWindowImpl->mpFrameData->mpFirstOverlap;
87 mpWindowImpl->mpFrameData->mpFirstOverlap = this;
89 // Overlap-Windows are by default the uppermost
90 mpWindowImpl->mpNext = pFirstOverlapParent->mpWindowImpl->mpFirstOverlap;
91 pFirstOverlapParent->mpWindowImpl->mpFirstOverlap = this;
92 if ( !pFirstOverlapParent->mpWindowImpl->mpLastOverlap )
93 pFirstOverlapParent->mpWindowImpl->mpLastOverlap = this;
94 else
95 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
97 else
99 if ( pParent->ImplIsOverlapWindow() )
100 mpWindowImpl->mpOverlapWindow = pParent;
101 else
102 mpWindowImpl->mpOverlapWindow = pParent->mpWindowImpl->mpOverlapWindow;
103 mpWindowImpl->mpPrev = pParent->mpWindowImpl->mpLastChild;
104 pParent->mpWindowImpl->mpLastChild = this;
105 if ( !pParent->mpWindowImpl->mpFirstChild )
106 pParent->mpWindowImpl->mpFirstChild = this;
107 else
108 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
112 void Window::ImplRemoveWindow( bool bRemoveFrameData )
114 // remove window from the lists
115 if ( !mpWindowImpl->mbFrame )
117 if ( ImplIsOverlapWindow() )
119 if ( mpWindowImpl->mpFrameData->mpFirstOverlap.get() == this )
120 mpWindowImpl->mpFrameData->mpFirstOverlap = mpWindowImpl->mpNextOverlap;
121 else
123 vcl::Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap;
124 while ( pTempWin->mpWindowImpl->mpNextOverlap.get() != this )
125 pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
126 pTempWin->mpWindowImpl->mpNextOverlap = mpWindowImpl->mpNextOverlap;
129 if ( mpWindowImpl->mpPrev )
130 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
131 else
132 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
133 if ( mpWindowImpl->mpNext )
134 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
135 else
136 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
138 else
140 if ( mpWindowImpl->mpPrev )
141 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
142 else if ( mpWindowImpl->mpParent )
143 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
144 if ( mpWindowImpl->mpNext )
145 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
146 else if ( mpWindowImpl->mpParent )
147 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
150 mpWindowImpl->mpPrev = nullptr;
151 mpWindowImpl->mpNext = nullptr;
154 if ( bRemoveFrameData )
156 // release the graphic
157 OutputDevice *pOutDev = GetOutDev();
158 pOutDev->ReleaseGraphics();
162 void Window::reorderWithinParent(sal_uInt16 nNewPosition)
164 sal_uInt16 nChildCount = 0;
165 vcl::Window *pSource = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
166 while (pSource)
168 if (nChildCount == nNewPosition)
169 break;
170 pSource = pSource->mpWindowImpl->mpNext;
171 nChildCount++;
174 if (pSource == this) //already at the right place
175 return;
177 ImplRemoveWindow(false);
179 if (pSource)
181 mpWindowImpl->mpNext = pSource;
182 mpWindowImpl->mpPrev = pSource->mpWindowImpl->mpPrev;
183 pSource->mpWindowImpl->mpPrev = this;
185 else
186 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
188 if (mpWindowImpl->mpPrev)
189 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
190 else
191 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
194 void Window::ImplToBottomChild()
196 if ( ImplIsOverlapWindow() || mpWindowImpl->mbReallyVisible || (mpWindowImpl->mpParent->mpWindowImpl->mpLastChild.get() == this) )
197 return;
199 // put the window to the end of the list
200 if ( mpWindowImpl->mpPrev )
201 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
202 else
204 // coverity[copy_paste_error : FALSE] - this is correct mpFirstChild, not mpNext
205 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
207 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
208 mpWindowImpl->mpPrev = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
209 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
210 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
211 mpWindowImpl->mpNext = nullptr;
214 void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData )
216 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplCalcToTop(): Is not an OverlapWindow" );
218 if ( mpWindowImpl->mbFrame )
219 return;
221 if ( !IsReallyVisible() )
222 return;
224 // calculate region, where the window overlaps with other windows
225 vcl::Region aRegion( GetOutputRectPixel() );
226 vcl::Region aInvalidateRegion;
227 ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion );
229 if ( !aInvalidateRegion.IsEmpty() )
231 ImplCalcToTopData* pData = new ImplCalcToTopData;
232 pPrevData->mpNext.reset(pData);
233 pData->mpWindow = this;
234 pData->mpInvalidateRegion.reset(new vcl::Region(std::move(aInvalidateRegion)));
238 void Window::ImplToTop( ToTopFlags nFlags )
240 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplToTop(): Is not an OverlapWindow" );
242 if ( mpWindowImpl->mbFrame )
244 // on a mouse click in the external window, it is the latter's
245 // responsibility to assure our frame is put in front
246 if ( !mpWindowImpl->mpFrameData->mbHasFocus &&
247 !mpWindowImpl->mpFrameData->mbSysObjFocus &&
248 !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl &&
249 !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl )
251 // do not bring floating windows on the client to top
252 if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) )
254 SalFrameToTop nSysFlags = SalFrameToTop::NONE;
255 if ( nFlags & ToTopFlags::RestoreWhenMin )
256 nSysFlags |= SalFrameToTop::RestoreWhenMin;
257 if ( nFlags & ToTopFlags::ForegroundTask )
258 nSysFlags |= SalFrameToTop::ForegroundTask;
259 if ( nFlags & ToTopFlags::GrabFocusOnly )
260 nSysFlags |= SalFrameToTop::GrabFocusOnly;
261 mpWindowImpl->mpFrame->ToTop( nSysFlags );
265 else
267 if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap.get() != this )
269 // remove window from the list
270 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
271 if ( mpWindowImpl->mpNext )
272 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
273 else
275 // coverity[copy_paste_error : FALSE] - this is correct mpLastOverlap, not mpPrev
276 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
279 // take AlwaysOnTop into account
280 bool bOnTop = IsAlwaysOnTopEnabled();
281 vcl::Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
282 if ( !bOnTop )
284 while ( pNextWin )
286 if ( !pNextWin->IsAlwaysOnTopEnabled() )
287 break;
288 pNextWin = pNextWin->mpWindowImpl->mpNext;
292 // add the window to the list again
293 mpWindowImpl->mpNext = pNextWin;
294 if ( pNextWin )
296 mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev;
297 pNextWin->mpWindowImpl->mpPrev = this;
299 else
301 mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
302 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
304 if ( mpWindowImpl->mpPrev )
305 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
306 else
307 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
309 // recalculate ClipRegion of this and all overlapping windows
310 if ( IsReallyVisible() )
312 mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows();
318 void Window::ImplStartToTop( ToTopFlags nFlags )
320 ImplCalcToTopData aStartData;
321 ImplCalcToTopData* pCurData;
322 vcl::Window* pOverlapWindow;
323 if ( ImplIsOverlapWindow() )
324 pOverlapWindow = this;
325 else
326 pOverlapWindow = mpWindowImpl->mpOverlapWindow;
328 // first calculate paint areas
329 vcl::Window* pTempOverlapWindow = pOverlapWindow;
330 aStartData.mpNext = nullptr;
331 pCurData = &aStartData;
334 pTempOverlapWindow->ImplCalcToTop( pCurData );
335 if ( pCurData->mpNext )
336 pCurData = pCurData->mpNext.get();
337 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
339 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
340 // next calculate the paint areas of the ChildOverlap windows
341 pTempOverlapWindow = mpWindowImpl->mpFirstOverlap;
342 while ( pTempOverlapWindow )
344 pTempOverlapWindow->ImplCalcToTop( pCurData );
345 if ( pCurData->mpNext )
346 pCurData = pCurData->mpNext.get();
347 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext;
350 // and next change the windows list
351 pTempOverlapWindow = pOverlapWindow;
354 pTempOverlapWindow->ImplToTop( nFlags );
355 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
357 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
358 // as last step invalidate the invalid areas
359 pCurData = aStartData.mpNext.get();
360 while ( pCurData )
362 pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion.get(), InvalidateFlags::Children );
363 pCurData = pCurData->mpNext.get();
367 void Window::ImplFocusToTop( ToTopFlags nFlags, bool bReallyVisible )
369 // do we need to fetch the focus?
370 if ( !(nFlags & ToTopFlags::NoGrabFocus) )
372 // first window with GrabFocus-Activate gets the focus
373 vcl::Window* pFocusWindow = this;
374 while ( !pFocusWindow->ImplIsOverlapWindow() )
376 // if the window has no BorderWindow, we
377 // should always find the belonging BorderWindow
378 if ( !pFocusWindow->mpWindowImpl->mpBorderWindow )
380 if ( pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus )
381 break;
383 pFocusWindow = pFocusWindow->ImplGetParent();
385 if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus) &&
386 !pFocusWindow->HasChildPathFocus( true ) )
387 pFocusWindow->GrabFocus();
390 if ( bReallyVisible )
391 ImplGenerateMouseMove();
394 void Window::ImplShowAllOverlaps()
396 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
397 while ( pOverlapWindow )
399 if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible )
401 pOverlapWindow->Show( true, ShowFlags::NoActivate );
402 pOverlapWindow->mpWindowImpl->mbOverlapVisible = false;
405 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
409 void Window::ImplHideAllOverlaps()
411 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
412 while ( pOverlapWindow )
414 if ( pOverlapWindow->IsVisible() )
416 pOverlapWindow->mpWindowImpl->mbOverlapVisible = true;
417 pOverlapWindow->Show( false );
420 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
424 void Window::ToTop( ToTopFlags nFlags )
426 if (!mpWindowImpl)
427 return;
429 ImplStartToTop( nFlags );
430 ImplFocusToTop( nFlags, IsReallyVisible() );
433 void Window::SetZOrder( vcl::Window* pRefWindow, ZOrderFlags nFlags )
436 if ( mpWindowImpl->mpBorderWindow )
438 mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags );
439 return;
442 if ( nFlags & ZOrderFlags::First )
444 if ( ImplIsOverlapWindow() )
445 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
446 else
447 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
448 nFlags |= ZOrderFlags::Before;
450 else if ( nFlags & ZOrderFlags::Last )
452 if ( ImplIsOverlapWindow() )
453 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
454 else
455 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
456 nFlags |= ZOrderFlags::Behind;
459 while ( pRefWindow && pRefWindow->mpWindowImpl->mpBorderWindow )
460 pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow;
461 if (!pRefWindow || pRefWindow == this || mpWindowImpl->mbFrame)
462 return;
464 SAL_WARN_IF( pRefWindow->mpWindowImpl->mpParent != mpWindowImpl->mpParent, "vcl", "Window::SetZOrder() - pRefWindow has other parent" );
465 if ( nFlags & ZOrderFlags::Before )
467 if ( pRefWindow->mpWindowImpl->mpPrev.get() == this )
468 return;
470 if ( ImplIsOverlapWindow() )
472 if ( mpWindowImpl->mpPrev )
473 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
474 else
475 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
476 if ( mpWindowImpl->mpNext )
477 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
478 else
479 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
480 if ( !pRefWindow->mpWindowImpl->mpPrev )
481 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
483 else
485 if ( mpWindowImpl->mpPrev )
486 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
487 else
488 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
489 if ( mpWindowImpl->mpNext )
490 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
491 else
492 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
493 if ( !pRefWindow->mpWindowImpl->mpPrev )
494 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
497 mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev;
498 mpWindowImpl->mpNext = pRefWindow;
499 if ( mpWindowImpl->mpPrev )
500 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
501 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
503 else if ( nFlags & ZOrderFlags::Behind )
505 if ( pRefWindow->mpWindowImpl->mpNext.get() == this )
506 return;
508 if ( ImplIsOverlapWindow() )
510 if ( mpWindowImpl->mpPrev )
511 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
512 else
513 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
514 if ( mpWindowImpl->mpNext )
515 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
516 else
517 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
518 if ( !pRefWindow->mpWindowImpl->mpNext )
519 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
521 else
523 if ( mpWindowImpl->mpPrev )
524 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
525 else
526 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
527 if ( mpWindowImpl->mpNext )
528 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
529 else
530 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
531 if ( !pRefWindow->mpWindowImpl->mpNext )
532 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
535 mpWindowImpl->mpPrev = pRefWindow;
536 mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext;
537 if ( mpWindowImpl->mpNext )
538 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
539 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
542 if ( !IsReallyVisible() )
543 return;
545 if ( !mpWindowImpl->mbInitWinClipRegion && mpWindowImpl->maWinClipRegion.IsEmpty() )
546 return;
548 bool bInitWinClipRegion = mpWindowImpl->mbInitWinClipRegion;
549 ImplSetClipFlag();
551 // When ClipRegion was not initialised, assume
552 // the window has not been sent, therefore do not
553 // trigger any Invalidates. This is an optimization
554 // for HTML documents with many controls. If this
555 // check gives problems, a flag should be introduced
556 // which tracks whether the window has already been
557 // emitted after Show
558 if ( bInitWinClipRegion )
559 return;
561 // Invalidate all windows which are next to each other
562 // Is INCOMPLETE !!!
563 tools::Rectangle aWinRect = GetOutputRectPixel();
564 vcl::Window* pWindow = nullptr;
565 if ( ImplIsOverlapWindow() )
567 if ( mpWindowImpl->mpOverlapWindow )
568 pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
570 else
571 pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
572 // Invalidate all windows in front of us and which are covered by us
573 while ( pWindow )
575 if ( pWindow == this )
576 break;
577 tools::Rectangle aCompRect = pWindow->GetOutputRectPixel();
578 if ( aWinRect.Overlaps( aCompRect ) )
579 pWindow->Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
580 pWindow = pWindow->mpWindowImpl->mpNext;
583 // If we are covered by a window in the background
584 // we should redraw it
585 while ( pWindow )
587 if ( pWindow != this )
589 tools::Rectangle aCompRect = pWindow->GetOutputRectPixel();
590 if ( aWinRect.Overlaps( aCompRect ) )
592 Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
593 break;
596 pWindow = pWindow->mpWindowImpl->mpNext;
600 void Window::EnableAlwaysOnTop( bool bEnable )
603 mpWindowImpl->mbAlwaysOnTop = bEnable;
605 if ( mpWindowImpl->mpBorderWindow )
606 mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable );
607 else if ( bEnable && IsReallyVisible() )
608 ToTop();
610 if ( mpWindowImpl->mbFrame )
611 mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable );
614 bool Window::IsTopWindow() const
616 if ( !mpWindowImpl || mpWindowImpl->mbInDispose )
617 return false;
619 // topwindows must be frames or they must have a borderwindow which is a frame
620 if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) )
621 return false;
623 ImplGetWinData();
624 if( mpWindowImpl->mpWinData->mnIsTopWindow == sal_uInt16(~0)) // still uninitialized
626 // #113722#, cache result of expensive queryInterface call
627 vcl::Window *pThisWin = const_cast<vcl::Window*>(this);
628 uno::Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY );
629 pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0;
631 return mpWindowImpl->mpWinData->mnIsTopWindow == 1;
634 vcl::Window* Window::ImplFindWindow( const Point& rFramePos )
636 vcl::Window* pTempWindow;
637 vcl::Window* pFindWindow;
639 // first check all overlapping windows
640 pTempWindow = mpWindowImpl->mpFirstOverlap;
641 while ( pTempWindow )
643 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
644 if ( pFindWindow )
645 return pFindWindow;
646 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
649 // then we check our window
650 if ( !mpWindowImpl->mbVisible )
651 return nullptr;
653 WindowHitTest nHitTest = ImplHitTest( rFramePos );
654 if ( nHitTest & WindowHitTest::Inside )
656 // and then we check all child windows
657 pTempWindow = mpWindowImpl->mpFirstChild;
658 while ( pTempWindow )
660 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
661 if ( pFindWindow )
662 return pFindWindow;
663 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
666 if ( nHitTest & WindowHitTest::Transparent )
667 return nullptr;
668 else
669 return this;
672 return nullptr;
675 bool Window::ImplIsRealParentPath( const vcl::Window* pWindow ) const
677 pWindow = pWindow->GetParent();
678 while ( pWindow )
680 if ( pWindow == this )
681 return true;
682 pWindow = pWindow->GetParent();
685 return false;
688 bool Window::ImplIsChild( const vcl::Window* pWindow, bool bSystemWindow ) const
692 if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
693 break;
695 pWindow = pWindow->ImplGetParent();
697 if ( pWindow == this )
698 return true;
700 while ( pWindow );
702 return false;
705 bool Window::ImplIsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
707 if ( this == pWindow )
708 return true;
709 return ImplIsChild( pWindow, bSystemWindow );
712 void Window::ImplResetReallyVisible()
714 bool bBecameReallyInvisible = mpWindowImpl->mbReallyVisible;
716 GetOutDev()->mbDevOutput = false;
717 mpWindowImpl->mbReallyVisible = false;
718 mpWindowImpl->mbReallyShown = false;
720 // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
721 // For this, the data member of the event must not be NULL.
722 // Previously, we did this in Window::Show, but there some events got lost in certain situations.
723 if( bBecameReallyInvisible && ImplIsAccessibleCandidate() )
724 CallEventListeners( VclEventId::WindowHide, this );
725 // TODO. It's kind of a hack that we're re-using the VclEventId::WindowHide. Normally, we should
726 // introduce another event which explicitly triggers the Accessibility implementations.
728 vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap;
729 while ( pWindow )
731 if ( pWindow->mpWindowImpl->mbReallyVisible )
732 pWindow->ImplResetReallyVisible();
733 pWindow = pWindow->mpWindowImpl->mpNext;
736 pWindow = mpWindowImpl->mpFirstChild;
737 while ( pWindow )
739 if ( pWindow->mpWindowImpl->mbReallyVisible )
740 pWindow->ImplResetReallyVisible();
741 pWindow = pWindow->mpWindowImpl->mpNext;
745 void Window::ImplUpdateWindowPtr( vcl::Window* pWindow )
747 if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
749 // release graphic
750 OutputDevice *pOutDev = GetOutDev();
751 pOutDev->ReleaseGraphics();
754 mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData;
755 if (mpWindowImpl->mpFrame != pWindow->mpWindowImpl->mpFrame)
757 mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame;
758 if (mpWindowImpl->mpSysObj)
759 mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
761 mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow;
762 if ( pWindow->ImplIsOverlapWindow() )
763 mpWindowImpl->mpOverlapWindow = pWindow;
764 else
765 mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow;
767 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
768 while ( pChild )
770 pChild->ImplUpdateWindowPtr( pWindow );
771 pChild = pChild->mpWindowImpl->mpNext;
775 void Window::ImplUpdateWindowPtr()
777 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
778 while ( pChild )
780 pChild->ImplUpdateWindowPtr( this );
781 pChild = pChild->mpWindowImpl->mpNext;
785 void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame )
787 bool bVisible = IsVisible();
788 Show( false );
789 ImplRemoveWindow( bNewFrame );
790 vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
791 ImplInsertWindow( ImplGetParent() );
792 mpWindowImpl->mpRealParent = pRealParent;
793 ImplUpdateWindowPtr();
794 if ( ImplUpdatePos() )
795 ImplUpdateSysObjPos();
797 if ( bNewFrame )
799 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
800 while ( pOverlapWindow )
802 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
803 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
804 pOverlapWindow = pNextOverlapWindow;
808 if ( bVisible )
809 Show();
812 SystemWindow* Window::GetSystemWindow() const
815 const vcl::Window* pWin = this;
816 while ( pWin && !pWin->IsSystemWindow() )
817 pWin = pWin->GetParent();
818 return static_cast<SystemWindow*>(const_cast<Window*>(pWin));
821 static SystemWindow *ImplGetLastSystemWindow( vcl::Window *pWin )
823 // get the most top-level system window, the one that contains the taskpanelist
824 SystemWindow *pSysWin = nullptr;
825 if( !pWin )
826 return pSysWin;
827 vcl::Window *pMyParent = pWin;
828 while ( pMyParent )
830 if ( pMyParent->IsSystemWindow() )
831 pSysWin = static_cast<SystemWindow*>(pMyParent);
832 pMyParent = pMyParent->GetParent();
834 return pSysWin;
837 void Window::SetParent( vcl::Window* pNewParent )
839 SAL_WARN_IF( !pNewParent, "vcl", "Window::SetParent(): pParent == NULL" );
840 SAL_WARN_IF( pNewParent == this, "vcl", "someone tried to reparent a window to itself" );
842 if( !pNewParent || pNewParent == this )
843 return;
845 // check if the taskpanelist would change and move the window pointer accordingly
846 SystemWindow *pSysWin = ImplGetLastSystemWindow(this);
847 SystemWindow *pNewSysWin = nullptr;
848 bool bChangeTaskPaneList = false;
849 if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) )
851 pNewSysWin = ImplGetLastSystemWindow( pNewParent );
852 if( pNewSysWin && pNewSysWin != pSysWin )
854 bChangeTaskPaneList = true;
855 pSysWin->GetTaskPaneList()->RemoveWindow( this );
858 // remove ownerdraw decorated windows from list in the top-most frame window
859 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
861 ::std::vector< VclPtr<vcl::Window> >& rList = ImplGetOwnerDrawList();
862 auto p = ::std::find( rList.begin(), rList.end(), VclPtr<vcl::Window>(this) );
863 if( p != rList.end() )
864 rList.erase( p );
867 ImplSetFrameParent( pNewParent );
869 if ( mpWindowImpl->mpBorderWindow )
871 mpWindowImpl->mpRealParent = pNewParent;
872 mpWindowImpl->mpBorderWindow->SetParent( pNewParent );
873 return;
876 if ( mpWindowImpl->mpParent.get() == pNewParent )
877 return;
879 if ( mpWindowImpl->mbFrame )
880 mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame );
882 bool bVisible = IsVisible();
883 Show( false, ShowFlags::NoFocusChange );
885 // check if the overlap window changes
886 vcl::Window* pOldOverlapWindow;
887 vcl::Window* pNewOverlapWindow = nullptr;
888 if ( ImplIsOverlapWindow() )
889 pOldOverlapWindow = nullptr;
890 else
892 pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow();
893 if ( mpWindowImpl->mpOverlapWindow.get() != pNewOverlapWindow )
894 pOldOverlapWindow = mpWindowImpl->mpOverlapWindow;
895 else
896 pOldOverlapWindow = nullptr;
899 // convert windows in the hierarchy
900 bool bFocusOverlapWin = HasChildPathFocus( true );
901 bool bFocusWin = HasChildPathFocus();
902 bool bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow;
903 if ( bNewFrame )
905 if ( mpWindowImpl->mpFrameData->mpFocusWin )
907 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) )
908 mpWindowImpl->mpFrameData->mpFocusWin = nullptr;
910 if ( mpWindowImpl->mpFrameData->mpMouseMoveWin )
912 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) )
913 mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr;
915 if ( mpWindowImpl->mpFrameData->mpMouseDownWin )
917 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) )
918 mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr;
921 ImplRemoveWindow( bNewFrame );
922 ImplInsertWindow( pNewParent );
923 if ( mpWindowImpl->mnParentClipMode & ParentClipMode::Clip )
924 pNewParent->mpWindowImpl->mbClipChildren = true;
925 ImplUpdateWindowPtr();
926 if ( ImplUpdatePos() )
927 ImplUpdateSysObjPos();
929 // If the Overlap-Window has changed, we need to test whether
930 // OverlapWindows that had the Child window as their parent
931 // need to be put into the window hierarchy.
932 if ( ImplIsOverlapWindow() )
934 if ( bNewFrame )
936 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
937 while ( pOverlapWindow )
939 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
940 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
941 pOverlapWindow = pNextOverlapWindow;
945 else if ( pOldOverlapWindow )
947 // reset Focus-Save
948 if ( bFocusWin ||
949 (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow &&
950 IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) )
951 pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
953 vcl::Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap;
954 while ( pOverlapWindow )
956 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
957 if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) )
958 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
959 pOverlapWindow = pNextOverlapWindow;
962 // update activate-status at next overlap window
963 if ( HasChildPathFocus( true ) )
964 ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
967 // also convert Activate-Status
968 if ( bNewFrame )
970 if ( (GetType() == WindowType::BORDERWINDOW) &&
971 (ImplGetWindow()->GetType() == WindowType::FLOATINGWINDOW) )
972 static_cast<ImplBorderWindow*>(this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus );
975 // when required give focus to new frame if
976 // FocusWindow is changed with SetParent()
977 if ( bFocusOverlapWin )
979 mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow();
980 if ( !mpWindowImpl->mpFrameData->mbHasFocus )
982 mpWindowImpl->mpFrame->ToTop( SalFrameToTop::NONE );
986 // Assure DragSource and DropTarget members are created
987 if ( bNewFrame )
989 GetDropTarget();
992 if( bChangeTaskPaneList )
993 pNewSysWin->GetTaskPaneList()->AddWindow( this );
995 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
996 ImplGetOwnerDrawList().emplace_back(this );
998 if ( bVisible )
999 Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
1002 bool Window::IsAncestorOf( const vcl::Window& rWindow ) const
1004 return ImplIsRealParentPath(&rWindow);
1007 sal_uInt16 Window::GetChildCount() const
1009 if (!mpWindowImpl)
1010 return 0;
1012 sal_uInt16 nChildCount = 0;
1013 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1014 while ( pChild )
1016 nChildCount++;
1017 pChild = pChild->mpWindowImpl->mpNext;
1020 return nChildCount;
1023 vcl::Window* Window::GetChild( sal_uInt16 nChild ) const
1025 if (!mpWindowImpl)
1026 return nullptr;
1028 sal_uInt16 nChildCount = 0;
1029 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1030 while ( pChild )
1032 if ( nChild == nChildCount )
1033 return pChild;
1034 pChild = pChild->mpWindowImpl->mpNext;
1035 nChildCount++;
1038 return nullptr;
1041 vcl::Window* Window::GetWindow( GetWindowType nType ) const
1043 if (!mpWindowImpl)
1044 return nullptr;
1046 switch ( nType )
1048 case GetWindowType::Parent:
1049 return mpWindowImpl->mpRealParent;
1051 case GetWindowType::FirstChild:
1052 return mpWindowImpl->mpFirstChild;
1054 case GetWindowType::LastChild:
1055 return mpWindowImpl->mpLastChild;
1057 case GetWindowType::Prev:
1058 return mpWindowImpl->mpPrev;
1060 case GetWindowType::Next:
1061 return mpWindowImpl->mpNext;
1063 case GetWindowType::FirstOverlap:
1064 return mpWindowImpl->mpFirstOverlap;
1066 case GetWindowType::Overlap:
1067 if ( ImplIsOverlapWindow() )
1068 return const_cast<vcl::Window*>(this);
1069 else
1070 return mpWindowImpl->mpOverlapWindow;
1072 case GetWindowType::ParentOverlap:
1073 if ( ImplIsOverlapWindow() )
1074 return mpWindowImpl->mpOverlapWindow;
1075 else
1076 return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow;
1078 case GetWindowType::Client:
1079 return this->ImplGetWindow();
1081 case GetWindowType::RealParent:
1082 return ImplGetParent();
1084 case GetWindowType::Frame:
1085 return mpWindowImpl->mpFrameWindow;
1087 case GetWindowType::Border:
1088 if ( mpWindowImpl->mpBorderWindow )
1089 return mpWindowImpl->mpBorderWindow->GetWindow( GetWindowType::Border );
1090 return const_cast<vcl::Window*>(this);
1092 case GetWindowType::FirstTopWindowChild:
1093 return ImplGetWinData()->maTopWindowChildren.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren.begin()).get();
1095 case GetWindowType::NextTopWindowSibling:
1097 if ( !mpWindowImpl->mpRealParent )
1098 return nullptr;
1099 const ::std::list< VclPtr<vcl::Window> >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
1100 ::std::list< VclPtr<vcl::Window> >::const_iterator myPos =
1101 ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
1102 if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) )
1103 return nullptr;
1104 return *myPos;
1109 return nullptr;
1112 bool Window::IsChild( const vcl::Window* pWindow ) const
1116 if ( pWindow->ImplIsOverlapWindow() )
1117 break;
1119 pWindow = pWindow->ImplGetParent();
1121 if ( pWindow == this )
1122 return true;
1124 while ( pWindow );
1126 return false;
1129 bool Window::IsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
1132 if ( this == pWindow )
1133 return true;
1134 return ImplIsChild( pWindow, bSystemWindow );
1137 void Window::ImplSetFrameParent( const vcl::Window* pParent )
1139 vcl::Window* pFrameWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
1140 while( pFrameWindow )
1142 // search all frames that are children of this window
1143 // and reparent them
1144 if( ImplIsRealParentPath( pFrameWindow ) )
1146 SAL_WARN_IF( mpWindowImpl->mpFrame == pFrameWindow->mpWindowImpl->mpFrame, "vcl", "SetFrameParent to own" );
1147 SAL_WARN_IF( !mpWindowImpl->mpFrame, "vcl", "no frame" );
1148 SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : nullptr;
1149 pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame );
1151 pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1155 } /* namespace vcl */
1157 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */