bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / window / stacking.cxx
blobc144eaa9bbd0239e83f41cb78da97960e837a811
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::lang;
36 using namespace ::com::sun::star::datatransfer::clipboard;
37 using namespace ::com::sun::star::datatransfer::dnd;
38 using namespace ::com::sun::star;
40 using ::com::sun::star::awt::XTopWindow;
42 struct ImplCalcToTopData
44 std::unique_ptr<ImplCalcToTopData> mpNext;
45 VclPtr<vcl::Window> mpWindow;
46 std::unique_ptr<vcl::Region> mpInvalidateRegion;
49 namespace vcl {
51 vcl::Window* Window::ImplGetTopmostFrameWindow()
53 vcl::Window *pTopmostParent = this;
54 while( pTopmostParent->ImplGetParent() )
55 pTopmostParent = pTopmostParent->ImplGetParent();
56 return pTopmostParent->mpWindowImpl->mpFrameWindow;
59 void Window::ImplInsertWindow( vcl::Window* pParent )
61 mpWindowImpl->mpParent = pParent;
62 mpWindowImpl->mpRealParent = pParent;
64 if ( !pParent || mpWindowImpl->mbFrame )
65 return;
67 // search frame window and set window frame data
68 vcl::Window* pFrameParent = pParent->mpWindowImpl->mpFrameWindow;
69 mpWindowImpl->mpFrameData = pFrameParent->mpWindowImpl->mpFrameData;
70 if (mpWindowImpl->mpFrame != pFrameParent->mpWindowImpl->mpFrame)
72 mpWindowImpl->mpFrame = pFrameParent->mpWindowImpl->mpFrame;
73 if (mpWindowImpl->mpSysObj)
74 mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
76 mpWindowImpl->mpFrameWindow = pFrameParent;
77 mpWindowImpl->mbFrame = false;
79 // search overlap window and insert window in list
80 if ( ImplIsOverlapWindow() )
82 vcl::Window* pFirstOverlapParent = pParent;
83 while ( !pFirstOverlapParent->ImplIsOverlapWindow() )
84 pFirstOverlapParent = pFirstOverlapParent->ImplGetParent();
85 mpWindowImpl->mpOverlapWindow = pFirstOverlapParent;
87 mpWindowImpl->mpNextOverlap = mpWindowImpl->mpFrameData->mpFirstOverlap;
88 mpWindowImpl->mpFrameData->mpFirstOverlap = this;
90 // Overlap-Windows are by default the uppermost
91 mpWindowImpl->mpNext = pFirstOverlapParent->mpWindowImpl->mpFirstOverlap;
92 pFirstOverlapParent->mpWindowImpl->mpFirstOverlap = this;
93 if ( !pFirstOverlapParent->mpWindowImpl->mpLastOverlap )
94 pFirstOverlapParent->mpWindowImpl->mpLastOverlap = this;
95 else
96 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
98 else
100 if ( pParent->ImplIsOverlapWindow() )
101 mpWindowImpl->mpOverlapWindow = pParent;
102 else
103 mpWindowImpl->mpOverlapWindow = pParent->mpWindowImpl->mpOverlapWindow;
104 mpWindowImpl->mpPrev = pParent->mpWindowImpl->mpLastChild;
105 pParent->mpWindowImpl->mpLastChild = this;
106 if ( !pParent->mpWindowImpl->mpFirstChild )
107 pParent->mpWindowImpl->mpFirstChild = this;
108 else
109 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
113 void Window::ImplRemoveWindow( bool bRemoveFrameData )
115 // remove window from the lists
116 if ( !mpWindowImpl->mbFrame )
118 if ( ImplIsOverlapWindow() )
120 if ( mpWindowImpl->mpFrameData->mpFirstOverlap.get() == this )
121 mpWindowImpl->mpFrameData->mpFirstOverlap = mpWindowImpl->mpNextOverlap;
122 else
124 vcl::Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap;
125 while ( pTempWin->mpWindowImpl->mpNextOverlap.get() != this )
126 pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
127 pTempWin->mpWindowImpl->mpNextOverlap = mpWindowImpl->mpNextOverlap;
130 if ( mpWindowImpl->mpPrev )
131 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
132 else
133 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
134 if ( mpWindowImpl->mpNext )
135 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
136 else
137 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
139 else
141 if ( mpWindowImpl->mpPrev )
142 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
143 else if ( mpWindowImpl->mpParent )
144 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
145 if ( mpWindowImpl->mpNext )
146 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
147 else if ( mpWindowImpl->mpParent )
148 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
151 mpWindowImpl->mpPrev = nullptr;
152 mpWindowImpl->mpNext = nullptr;
155 if ( bRemoveFrameData )
157 // release the graphic
158 OutputDevice *pOutDev = GetOutDev();
159 pOutDev->ReleaseGraphics();
163 void Window::reorderWithinParent(sal_uInt16 nNewPosition)
165 sal_uInt16 nChildCount = 0;
166 vcl::Window *pSource = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
167 while (pSource)
169 if (nChildCount == nNewPosition)
170 break;
171 pSource = pSource->mpWindowImpl->mpNext;
172 nChildCount++;
175 if (pSource == this) //already at the right place
176 return;
178 ImplRemoveWindow(false);
180 if (pSource)
182 mpWindowImpl->mpNext = pSource;
183 mpWindowImpl->mpPrev = pSource->mpWindowImpl->mpPrev;
184 pSource->mpWindowImpl->mpPrev = this;
186 else
187 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
189 if (mpWindowImpl->mpPrev)
190 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
191 else
192 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
195 void Window::ImplToBottomChild()
197 if ( ImplIsOverlapWindow() || mpWindowImpl->mbReallyVisible || (mpWindowImpl->mpParent->mpWindowImpl->mpLastChild.get() == this) )
198 return;
200 // put the window to the end of the list
201 if ( mpWindowImpl->mpPrev )
202 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
203 else
204 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
205 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
206 mpWindowImpl->mpPrev = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
207 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
208 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
209 mpWindowImpl->mpNext = nullptr;
212 void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData )
214 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplCalcToTop(): Is not an OverlapWindow" );
216 if ( mpWindowImpl->mbFrame )
217 return;
219 if ( !IsReallyVisible() )
220 return;
222 // calculate region, where the window overlaps with other windows
223 vcl::Region aRegion( GetOutputRectPixel() );
224 vcl::Region aInvalidateRegion;
225 ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion );
227 if ( !aInvalidateRegion.IsEmpty() )
229 ImplCalcToTopData* pData = new ImplCalcToTopData;
230 pPrevData->mpNext.reset(pData);
231 pData->mpWindow = this;
232 pData->mpInvalidateRegion.reset(new vcl::Region( aInvalidateRegion ));
236 void Window::ImplToTop( ToTopFlags nFlags )
238 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplToTop(): Is not an OverlapWindow" );
240 if ( mpWindowImpl->mbFrame )
242 // on a mouse click in the external window, it is the latter's
243 // responsibility to assure our frame is put in front
244 if ( !mpWindowImpl->mpFrameData->mbHasFocus &&
245 !mpWindowImpl->mpFrameData->mbSysObjFocus &&
246 !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl &&
247 !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl )
249 // do not bring floating windows on the client to top
250 if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) )
252 SalFrameToTop nSysFlags = SalFrameToTop::NONE;
253 if ( nFlags & ToTopFlags::RestoreWhenMin )
254 nSysFlags |= SalFrameToTop::RestoreWhenMin;
255 if ( nFlags & ToTopFlags::ForegroundTask )
256 nSysFlags |= SalFrameToTop::ForegroundTask;
257 if ( nFlags & ToTopFlags::GrabFocusOnly )
258 nSysFlags |= SalFrameToTop::GrabFocusOnly;
259 mpWindowImpl->mpFrame->ToTop( nSysFlags );
263 else
265 if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap.get() != this )
267 // remove window from the list
268 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
269 if ( mpWindowImpl->mpNext )
270 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
271 else
272 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
274 // take AlwaysOnTop into account
275 bool bOnTop = IsAlwaysOnTopEnabled();
276 vcl::Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
277 if ( !bOnTop )
279 while ( pNextWin )
281 if ( !pNextWin->IsAlwaysOnTopEnabled() )
282 break;
283 pNextWin = pNextWin->mpWindowImpl->mpNext;
287 // add the window to the list again
288 mpWindowImpl->mpNext = pNextWin;
289 if ( pNextWin )
291 mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev;
292 pNextWin->mpWindowImpl->mpPrev = this;
294 else
296 mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
297 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
299 if ( mpWindowImpl->mpPrev )
300 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
301 else
302 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
304 // recalculate ClipRegion of this and all overlapping windows
305 if ( IsReallyVisible() )
307 mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows();
313 void Window::ImplStartToTop( ToTopFlags nFlags )
315 ImplCalcToTopData aStartData;
316 ImplCalcToTopData* pCurData;
317 vcl::Window* pOverlapWindow;
318 if ( ImplIsOverlapWindow() )
319 pOverlapWindow = this;
320 else
321 pOverlapWindow = mpWindowImpl->mpOverlapWindow;
323 // first calculate paint areas
324 vcl::Window* pTempOverlapWindow = pOverlapWindow;
325 aStartData.mpNext = nullptr;
326 pCurData = &aStartData;
329 pTempOverlapWindow->ImplCalcToTop( pCurData );
330 if ( pCurData->mpNext )
331 pCurData = pCurData->mpNext.get();
332 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
334 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
335 // next calculate the paint areas of the ChildOverlap windows
336 pTempOverlapWindow = mpWindowImpl->mpFirstOverlap;
337 while ( pTempOverlapWindow )
339 pTempOverlapWindow->ImplCalcToTop( pCurData );
340 if ( pCurData->mpNext )
341 pCurData = pCurData->mpNext.get();
342 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext;
345 // and next change the windows list
346 pTempOverlapWindow = pOverlapWindow;
349 pTempOverlapWindow->ImplToTop( nFlags );
350 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
352 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
353 // as last step invalidate the invalid areas
354 pCurData = aStartData.mpNext.get();
355 while ( pCurData )
357 pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion.get(), InvalidateFlags::Children );
358 pCurData = pCurData->mpNext.get();
362 void Window::ImplFocusToTop( ToTopFlags nFlags, bool bReallyVisible )
364 // do we need to fetch the focus?
365 if ( !(nFlags & ToTopFlags::NoGrabFocus) )
367 // first window with GrabFocus-Activate gets the focus
368 vcl::Window* pFocusWindow = this;
369 while ( !pFocusWindow->ImplIsOverlapWindow() )
371 // if the window has no BorderWindow, we
372 // should always find the belonging BorderWindow
373 if ( !pFocusWindow->mpWindowImpl->mpBorderWindow )
375 if ( pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus )
376 break;
378 pFocusWindow = pFocusWindow->ImplGetParent();
380 if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus) &&
381 !pFocusWindow->HasChildPathFocus( true ) )
382 pFocusWindow->GrabFocus();
385 if ( bReallyVisible )
386 ImplGenerateMouseMove();
389 void Window::ImplShowAllOverlaps()
391 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
392 while ( pOverlapWindow )
394 if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible )
396 pOverlapWindow->Show( true, ShowFlags::NoActivate );
397 pOverlapWindow->mpWindowImpl->mbOverlapVisible = false;
400 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
404 void Window::ImplHideAllOverlaps()
406 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
407 while ( pOverlapWindow )
409 if ( pOverlapWindow->IsVisible() )
411 pOverlapWindow->mpWindowImpl->mbOverlapVisible = true;
412 pOverlapWindow->Show( false );
415 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
419 void Window::ToTop( ToTopFlags nFlags )
421 if (!mpWindowImpl)
422 return;
424 ImplStartToTop( nFlags );
425 ImplFocusToTop( nFlags, IsReallyVisible() );
428 void Window::SetZOrder( vcl::Window* pRefWindow, ZOrderFlags nFlags )
431 if ( mpWindowImpl->mpBorderWindow )
433 mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags );
434 return;
437 if ( nFlags & ZOrderFlags::First )
439 if ( ImplIsOverlapWindow() )
440 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
441 else
442 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
443 nFlags |= ZOrderFlags::Before;
445 else if ( nFlags & ZOrderFlags::Last )
447 if ( ImplIsOverlapWindow() )
448 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
449 else
450 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
451 nFlags |= ZOrderFlags::Behind;
454 while ( pRefWindow && pRefWindow->mpWindowImpl->mpBorderWindow )
455 pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow;
456 if (!pRefWindow || pRefWindow == this || mpWindowImpl->mbFrame)
457 return;
459 SAL_WARN_IF( pRefWindow->mpWindowImpl->mpParent != mpWindowImpl->mpParent, "vcl", "Window::SetZOrder() - pRefWindow has other parent" );
460 if ( nFlags & ZOrderFlags::Before )
462 if ( pRefWindow->mpWindowImpl->mpPrev.get() == this )
463 return;
465 if ( ImplIsOverlapWindow() )
467 if ( mpWindowImpl->mpPrev )
468 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
469 else
470 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
471 if ( mpWindowImpl->mpNext )
472 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
473 else
474 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
475 if ( !pRefWindow->mpWindowImpl->mpPrev )
476 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
478 else
480 if ( mpWindowImpl->mpPrev )
481 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
482 else
483 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
484 if ( mpWindowImpl->mpNext )
485 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
486 else
487 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
488 if ( !pRefWindow->mpWindowImpl->mpPrev )
489 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
492 mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev;
493 mpWindowImpl->mpNext = pRefWindow;
494 if ( mpWindowImpl->mpPrev )
495 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
496 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
498 else if ( nFlags & ZOrderFlags::Behind )
500 if ( pRefWindow->mpWindowImpl->mpNext.get() == this )
501 return;
503 if ( ImplIsOverlapWindow() )
505 if ( mpWindowImpl->mpPrev )
506 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
507 else
508 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
509 if ( mpWindowImpl->mpNext )
510 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
511 else
512 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
513 if ( !pRefWindow->mpWindowImpl->mpNext )
514 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
516 else
518 if ( mpWindowImpl->mpPrev )
519 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
520 else
521 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
522 if ( mpWindowImpl->mpNext )
523 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
524 else
525 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
526 if ( !pRefWindow->mpWindowImpl->mpNext )
527 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
530 mpWindowImpl->mpPrev = pRefWindow;
531 mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext;
532 if ( mpWindowImpl->mpNext )
533 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
534 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
537 if ( !IsReallyVisible() )
538 return;
540 if ( !mpWindowImpl->mbInitWinClipRegion && mpWindowImpl->maWinClipRegion.IsEmpty() )
541 return;
543 bool bInitWinClipRegion = mpWindowImpl->mbInitWinClipRegion;
544 ImplSetClipFlag();
546 // When ClipRegion was not initialised, assume
547 // the window has not been sent, therefore do not
548 // trigger any Invalidates. This is an optimization
549 // for HTML documents with many controls. If this
550 // check gives problems, a flag should be introduced
551 // which tracks whether the window has already been
552 // emitted after Show
553 if ( bInitWinClipRegion )
554 return;
556 // Invalidate all windows which are next to each other
557 // Is INCOMPLETE !!!
558 tools::Rectangle aWinRect = GetOutputRectPixel();
559 vcl::Window* pWindow = nullptr;
560 if ( ImplIsOverlapWindow() )
562 if ( mpWindowImpl->mpOverlapWindow )
563 pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
565 else
566 pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
567 // Invalidate all windows in front of us and which are covered by us
568 while ( pWindow )
570 if ( pWindow == this )
571 break;
572 tools::Rectangle aCompRect = pWindow->GetOutputRectPixel();
573 if ( aWinRect.Overlaps( aCompRect ) )
574 pWindow->Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
575 pWindow = pWindow->mpWindowImpl->mpNext;
578 // If we are covered by a window in the background
579 // we should redraw it
580 while ( pWindow )
582 if ( pWindow != this )
584 tools::Rectangle aCompRect = pWindow->GetOutputRectPixel();
585 if ( aWinRect.Overlaps( aCompRect ) )
587 Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
588 break;
591 pWindow = pWindow->mpWindowImpl->mpNext;
595 void Window::EnableAlwaysOnTop( bool bEnable )
598 mpWindowImpl->mbAlwaysOnTop = bEnable;
600 if ( mpWindowImpl->mpBorderWindow )
601 mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable );
602 else if ( bEnable && IsReallyVisible() )
603 ToTop();
605 if ( mpWindowImpl->mbFrame )
606 mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable );
609 bool Window::IsTopWindow() const
611 if ( !mpWindowImpl || mpWindowImpl->mbInDispose )
612 return false;
614 // topwindows must be frames or they must have a borderwindow which is a frame
615 if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) )
616 return false;
618 ImplGetWinData();
619 if( mpWindowImpl->mpWinData->mnIsTopWindow == sal_uInt16(~0)) // still uninitialized
621 // #113722#, cache result of expensive queryInterface call
622 vcl::Window *pThisWin = const_cast<vcl::Window*>(this);
623 uno::Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY );
624 pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0;
626 return mpWindowImpl->mpWinData->mnIsTopWindow == 1;
629 vcl::Window* Window::ImplFindWindow( const Point& rFramePos )
631 vcl::Window* pTempWindow;
632 vcl::Window* pFindWindow;
634 // first check all overlapping windows
635 pTempWindow = mpWindowImpl->mpFirstOverlap;
636 while ( pTempWindow )
638 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
639 if ( pFindWindow )
640 return pFindWindow;
641 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
644 // then we check our window
645 if ( !mpWindowImpl->mbVisible )
646 return nullptr;
648 WindowHitTest nHitTest = ImplHitTest( rFramePos );
649 if ( nHitTest & WindowHitTest::Inside )
651 // and then we check all child windows
652 pTempWindow = mpWindowImpl->mpFirstChild;
653 while ( pTempWindow )
655 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
656 if ( pFindWindow )
657 return pFindWindow;
658 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
661 if ( nHitTest & WindowHitTest::Transparent )
662 return nullptr;
663 else
664 return this;
667 return nullptr;
670 bool Window::ImplIsRealParentPath( const vcl::Window* pWindow ) const
672 pWindow = pWindow->GetParent();
673 while ( pWindow )
675 if ( pWindow == this )
676 return true;
677 pWindow = pWindow->GetParent();
680 return false;
683 bool Window::ImplIsChild( const vcl::Window* pWindow, bool bSystemWindow ) const
687 if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
688 break;
690 pWindow = pWindow->ImplGetParent();
692 if ( pWindow == this )
693 return true;
695 while ( pWindow );
697 return false;
700 bool Window::ImplIsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
702 if ( this == pWindow )
703 return true;
704 return ImplIsChild( pWindow, bSystemWindow );
707 void Window::ImplResetReallyVisible()
709 bool bBecameReallyInvisible = mpWindowImpl->mbReallyVisible;
711 GetOutDev()->mbDevOutput = false;
712 mpWindowImpl->mbReallyVisible = false;
713 mpWindowImpl->mbReallyShown = false;
715 // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
716 // For this, the data member of the event must not be NULL.
717 // Previously, we did this in Window::Show, but there some events got lost in certain situations.
718 if( bBecameReallyInvisible && ImplIsAccessibleCandidate() )
719 CallEventListeners( VclEventId::WindowHide, this );
720 // TODO. It's kind of a hack that we're re-using the VclEventId::WindowHide. Normally, we should
721 // introduce another event which explicitly triggers the Accessibility implementations.
723 vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap;
724 while ( pWindow )
726 if ( pWindow->mpWindowImpl->mbReallyVisible )
727 pWindow->ImplResetReallyVisible();
728 pWindow = pWindow->mpWindowImpl->mpNext;
731 pWindow = mpWindowImpl->mpFirstChild;
732 while ( pWindow )
734 if ( pWindow->mpWindowImpl->mbReallyVisible )
735 pWindow->ImplResetReallyVisible();
736 pWindow = pWindow->mpWindowImpl->mpNext;
740 void Window::ImplUpdateWindowPtr( vcl::Window* pWindow )
742 if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
744 // release graphic
745 OutputDevice *pOutDev = GetOutDev();
746 pOutDev->ReleaseGraphics();
749 mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData;
750 if (mpWindowImpl->mpFrame != pWindow->mpWindowImpl->mpFrame)
752 mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame;
753 if (mpWindowImpl->mpSysObj)
754 mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
756 mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow;
757 if ( pWindow->ImplIsOverlapWindow() )
758 mpWindowImpl->mpOverlapWindow = pWindow;
759 else
760 mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow;
762 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
763 while ( pChild )
765 pChild->ImplUpdateWindowPtr( pWindow );
766 pChild = pChild->mpWindowImpl->mpNext;
770 void Window::ImplUpdateWindowPtr()
772 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
773 while ( pChild )
775 pChild->ImplUpdateWindowPtr( this );
776 pChild = pChild->mpWindowImpl->mpNext;
780 void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame )
782 bool bVisible = IsVisible();
783 Show( false );
784 ImplRemoveWindow( bNewFrame );
785 vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
786 ImplInsertWindow( ImplGetParent() );
787 mpWindowImpl->mpRealParent = pRealParent;
788 ImplUpdateWindowPtr();
789 if ( ImplUpdatePos() )
790 ImplUpdateSysObjPos();
792 if ( bNewFrame )
794 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
795 while ( pOverlapWindow )
797 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
798 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
799 pOverlapWindow = pNextOverlapWindow;
803 if ( bVisible )
804 Show();
807 SystemWindow* Window::GetSystemWindow() const
810 const vcl::Window* pWin = this;
811 while ( pWin && !pWin->IsSystemWindow() )
812 pWin = pWin->GetParent();
813 return static_cast<SystemWindow*>(const_cast<Window*>(pWin));
816 static SystemWindow *ImplGetLastSystemWindow( vcl::Window *pWin )
818 // get the most top-level system window, the one that contains the taskpanelist
819 SystemWindow *pSysWin = nullptr;
820 if( !pWin )
821 return pSysWin;
822 vcl::Window *pMyParent = pWin;
823 while ( pMyParent )
825 if ( pMyParent->IsSystemWindow() )
826 pSysWin = static_cast<SystemWindow*>(pMyParent);
827 pMyParent = pMyParent->GetParent();
829 return pSysWin;
832 void Window::SetParent( vcl::Window* pNewParent )
834 SAL_WARN_IF( !pNewParent, "vcl", "Window::SetParent(): pParent == NULL" );
835 SAL_WARN_IF( pNewParent == this, "vcl", "someone tried to reparent a window to itself" );
837 if( !pNewParent || pNewParent == this )
838 return;
840 // check if the taskpanelist would change and move the window pointer accordingly
841 SystemWindow *pSysWin = ImplGetLastSystemWindow(this);
842 SystemWindow *pNewSysWin = nullptr;
843 bool bChangeTaskPaneList = false;
844 if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) )
846 pNewSysWin = ImplGetLastSystemWindow( pNewParent );
847 if( pNewSysWin && pNewSysWin != pSysWin )
849 bChangeTaskPaneList = true;
850 pSysWin->GetTaskPaneList()->RemoveWindow( this );
853 // remove ownerdraw decorated windows from list in the top-most frame window
854 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
856 ::std::vector< VclPtr<vcl::Window> >& rList = ImplGetOwnerDrawList();
857 auto p = ::std::find( rList.begin(), rList.end(), VclPtr<vcl::Window>(this) );
858 if( p != rList.end() )
859 rList.erase( p );
862 ImplSetFrameParent( pNewParent );
864 if ( mpWindowImpl->mpBorderWindow )
866 mpWindowImpl->mpRealParent = pNewParent;
867 mpWindowImpl->mpBorderWindow->SetParent( pNewParent );
868 return;
871 if ( mpWindowImpl->mpParent.get() == pNewParent )
872 return;
874 if ( mpWindowImpl->mbFrame )
875 mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame );
877 bool bVisible = IsVisible();
878 Show( false, ShowFlags::NoFocusChange );
880 // check if the overlap window changes
881 vcl::Window* pOldOverlapWindow;
882 vcl::Window* pNewOverlapWindow = nullptr;
883 if ( ImplIsOverlapWindow() )
884 pOldOverlapWindow = nullptr;
885 else
887 pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow();
888 if ( mpWindowImpl->mpOverlapWindow.get() != pNewOverlapWindow )
889 pOldOverlapWindow = mpWindowImpl->mpOverlapWindow;
890 else
891 pOldOverlapWindow = nullptr;
894 // convert windows in the hierarchy
895 bool bFocusOverlapWin = HasChildPathFocus( true );
896 bool bFocusWin = HasChildPathFocus();
897 bool bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow;
898 if ( bNewFrame )
900 if ( mpWindowImpl->mpFrameData->mpFocusWin )
902 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) )
903 mpWindowImpl->mpFrameData->mpFocusWin = nullptr;
905 if ( mpWindowImpl->mpFrameData->mpMouseMoveWin )
907 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) )
908 mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr;
910 if ( mpWindowImpl->mpFrameData->mpMouseDownWin )
912 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) )
913 mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr;
916 ImplRemoveWindow( bNewFrame );
917 ImplInsertWindow( pNewParent );
918 if ( mpWindowImpl->mnParentClipMode & ParentClipMode::Clip )
919 pNewParent->mpWindowImpl->mbClipChildren = true;
920 ImplUpdateWindowPtr();
921 if ( ImplUpdatePos() )
922 ImplUpdateSysObjPos();
924 // If the Overlap-Window has changed, we need to test whether
925 // OverlapWindows that had the Child window as their parent
926 // need to be put into the window hierarchy.
927 if ( ImplIsOverlapWindow() )
929 if ( bNewFrame )
931 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
932 while ( pOverlapWindow )
934 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
935 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
936 pOverlapWindow = pNextOverlapWindow;
940 else if ( pOldOverlapWindow )
942 // reset Focus-Save
943 if ( bFocusWin ||
944 (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow &&
945 IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) )
946 pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
948 vcl::Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap;
949 while ( pOverlapWindow )
951 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
952 if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) )
953 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
954 pOverlapWindow = pNextOverlapWindow;
957 // update activate-status at next overlap window
958 if ( HasChildPathFocus( true ) )
959 ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
962 // also convert Activate-Status
963 if ( bNewFrame )
965 if ( (GetType() == WindowType::BORDERWINDOW) &&
966 (ImplGetWindow()->GetType() == WindowType::FLOATINGWINDOW) )
967 static_cast<ImplBorderWindow*>(this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus );
970 // when required give focus to new frame if
971 // FocusWindow is changed with SetParent()
972 if ( bFocusOverlapWin )
974 mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow();
975 if ( !mpWindowImpl->mpFrameData->mbHasFocus )
977 mpWindowImpl->mpFrame->ToTop( SalFrameToTop::NONE );
981 // Assure DragSource and DropTarget members are created
982 if ( bNewFrame )
984 GetDropTarget();
987 if( bChangeTaskPaneList )
988 pNewSysWin->GetTaskPaneList()->AddWindow( this );
990 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
991 ImplGetOwnerDrawList().emplace_back(this );
993 if ( bVisible )
994 Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
997 bool Window::IsAncestorOf( const vcl::Window& rWindow ) const
999 return ImplIsRealParentPath(&rWindow);
1002 sal_uInt16 Window::GetChildCount() const
1004 if (!mpWindowImpl)
1005 return 0;
1007 sal_uInt16 nChildCount = 0;
1008 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1009 while ( pChild )
1011 nChildCount++;
1012 pChild = pChild->mpWindowImpl->mpNext;
1015 return nChildCount;
1018 vcl::Window* Window::GetChild( sal_uInt16 nChild ) const
1020 if (!mpWindowImpl)
1021 return nullptr;
1023 sal_uInt16 nChildCount = 0;
1024 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1025 while ( pChild )
1027 if ( nChild == nChildCount )
1028 return pChild;
1029 pChild = pChild->mpWindowImpl->mpNext;
1030 nChildCount++;
1033 return nullptr;
1036 vcl::Window* Window::GetWindow( GetWindowType nType ) const
1038 if (!mpWindowImpl)
1039 return nullptr;
1041 switch ( nType )
1043 case GetWindowType::Parent:
1044 return mpWindowImpl->mpRealParent;
1046 case GetWindowType::FirstChild:
1047 return mpWindowImpl->mpFirstChild;
1049 case GetWindowType::LastChild:
1050 return mpWindowImpl->mpLastChild;
1052 case GetWindowType::Prev:
1053 return mpWindowImpl->mpPrev;
1055 case GetWindowType::Next:
1056 return mpWindowImpl->mpNext;
1058 case GetWindowType::FirstOverlap:
1059 return mpWindowImpl->mpFirstOverlap;
1061 case GetWindowType::Overlap:
1062 if ( ImplIsOverlapWindow() )
1063 return const_cast<vcl::Window*>(this);
1064 else
1065 return mpWindowImpl->mpOverlapWindow;
1067 case GetWindowType::ParentOverlap:
1068 if ( ImplIsOverlapWindow() )
1069 return mpWindowImpl->mpOverlapWindow;
1070 else
1071 return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow;
1073 case GetWindowType::Client:
1074 return this->ImplGetWindow();
1076 case GetWindowType::RealParent:
1077 return ImplGetParent();
1079 case GetWindowType::Frame:
1080 return mpWindowImpl->mpFrameWindow;
1082 case GetWindowType::Border:
1083 if ( mpWindowImpl->mpBorderWindow )
1084 return mpWindowImpl->mpBorderWindow->GetWindow( GetWindowType::Border );
1085 return const_cast<vcl::Window*>(this);
1087 case GetWindowType::FirstTopWindowChild:
1088 return ImplGetWinData()->maTopWindowChildren.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren.begin()).get();
1090 case GetWindowType::NextTopWindowSibling:
1092 if ( !mpWindowImpl->mpRealParent )
1093 return nullptr;
1094 const ::std::list< VclPtr<vcl::Window> >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
1095 ::std::list< VclPtr<vcl::Window> >::const_iterator myPos =
1096 ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
1097 if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) )
1098 return nullptr;
1099 return *myPos;
1104 return nullptr;
1107 bool Window::IsChild( const vcl::Window* pWindow ) const
1111 if ( pWindow->ImplIsOverlapWindow() )
1112 break;
1114 pWindow = pWindow->ImplGetParent();
1116 if ( pWindow == this )
1117 return true;
1119 while ( pWindow );
1121 return false;
1124 bool Window::IsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
1127 if ( this == pWindow )
1128 return true;
1129 return ImplIsChild( pWindow, bSystemWindow );
1132 void Window::ImplSetFrameParent( const vcl::Window* pParent )
1134 vcl::Window* pFrameWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
1135 while( pFrameWindow )
1137 // search all frames that are children of this window
1138 // and reparent them
1139 if( ImplIsRealParentPath( pFrameWindow ) )
1141 SAL_WARN_IF( mpWindowImpl->mpFrame == pFrameWindow->mpWindowImpl->mpFrame, "vcl", "SetFrameParent to own" );
1142 SAL_WARN_IF( !mpWindowImpl->mpFrame, "vcl", "no frame" );
1143 SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : nullptr;
1144 pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame );
1146 pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1150 } /* namespace vcl */
1152 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */