build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / stacking.cxx
blob06720a58889627cb9fcb66787cfe13afab311391
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/window.hxx>
21 #include <vcl/taskpanelist.hxx>
23 // declare system types in sysdata.hxx
24 #include <vcl/sysdata.hxx>
26 #include <salframe.hxx>
27 #include <salobj.hxx>
28 #include <salgdi.hxx>
29 #include <svdata.hxx>
30 #include <window.h>
31 #include <brdwin.hxx>
32 #include <helpwin.hxx>
34 #include <com/sun/star/awt/XTopWindow.hpp>
36 #include <set>
37 #include <typeinfo>
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::datatransfer::clipboard;
42 using namespace ::com::sun::star::datatransfer::dnd;
43 using namespace ::com::sun::star;
45 using ::com::sun::star::awt::XTopWindow;
47 struct ImplCalcToTopData
49 ImplCalcToTopData* mpNext;
50 VclPtr<vcl::Window> mpWindow;
51 vcl::Region* mpInvalidateRegion;
54 namespace vcl {
56 vcl::Window* Window::ImplGetTopmostFrameWindow()
58 vcl::Window *pTopmostParent = this;
59 while( pTopmostParent->ImplGetParent() )
60 pTopmostParent = pTopmostParent->ImplGetParent();
61 return pTopmostParent->mpWindowImpl->mpFrameWindow;
64 void Window::ImplInsertWindow( vcl::Window* pParent )
66 mpWindowImpl->mpParent = pParent;
67 mpWindowImpl->mpRealParent = pParent;
69 if ( pParent && !mpWindowImpl->mbFrame )
71 // search frame window and set window frame data
72 vcl::Window* pFrameParent = pParent->mpWindowImpl->mpFrameWindow;
73 mpWindowImpl->mpFrameData = pFrameParent->mpWindowImpl->mpFrameData;
74 mpWindowImpl->mpFrame = pFrameParent->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;
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) )
199 // put the window to the end of the list
200 if ( mpWindowImpl->mpPrev )
201 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
202 else
203 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
204 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
205 mpWindowImpl->mpPrev = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
206 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
207 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
208 mpWindowImpl->mpNext = nullptr;
212 void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData )
214 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplCalcToTop(): Is not a OverlapWindow" );
216 if ( !mpWindowImpl->mbFrame )
218 if ( IsReallyVisible() )
220 // calculate region, where the window overlaps with other windows
221 Point aPoint( mnOutOffX, mnOutOffY );
222 vcl::Region aRegion( Rectangle( aPoint,
223 Size( mnOutWidth, mnOutHeight ) ) );
224 vcl::Region aInvalidateRegion;
225 ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion );
227 if ( !aInvalidateRegion.IsEmpty() )
229 ImplCalcToTopData* pData = new ImplCalcToTopData;
230 pPrevData->mpNext = pData;
231 pData->mpNext = nullptr;
232 pData->mpWindow = this;
233 pData->mpInvalidateRegion = new vcl::Region( aInvalidateRegion );
239 void Window::ImplToTop( ToTopFlags nFlags )
241 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplToTop(): Is not a OverlapWindow" );
243 if ( mpWindowImpl->mbFrame )
245 // on a mouse click in the external window, it is the latter's
246 // responsibility to assure our frame is put in front
247 if ( !mpWindowImpl->mpFrameData->mbHasFocus &&
248 !mpWindowImpl->mpFrameData->mbSysObjFocus &&
249 !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl &&
250 !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl )
252 // do not bring floating windows on the client to top
253 if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) )
255 SalFrameToTop nSysFlags = SalFrameToTop::NONE;
256 if ( nFlags & ToTopFlags::RestoreWhenMin )
257 nSysFlags |= SalFrameToTop::RestoreWhenMin;
258 if ( nFlags & ToTopFlags::ForegroundTask )
259 nSysFlags |= SalFrameToTop::ForegroundTask;
260 if ( nFlags & ToTopFlags::GrabFocusOnly )
261 nSysFlags |= SalFrameToTop::GrabFocusOnly;
262 mpWindowImpl->mpFrame->ToTop( nSysFlags );
266 else
268 if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap.get() != this )
270 // remove window from the list
271 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
272 if ( mpWindowImpl->mpNext )
273 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
274 else
275 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
277 // take AlwaysOnTop into account
278 bool bOnTop = IsAlwaysOnTopEnabled();
279 vcl::Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
280 if ( !bOnTop )
282 while ( pNextWin )
284 if ( !pNextWin->IsAlwaysOnTopEnabled() )
285 break;
286 pNextWin = pNextWin->mpWindowImpl->mpNext;
290 // add the window to the list again
291 mpWindowImpl->mpNext = pNextWin;
292 if ( pNextWin )
294 mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev;
295 pNextWin->mpWindowImpl->mpPrev = this;
297 else
299 mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
300 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
302 if ( mpWindowImpl->mpPrev )
303 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
304 else
305 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
307 // recalculate ClipRegion of this and all overlapping windows
308 if ( IsReallyVisible() )
310 mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows();
316 void Window::ImplStartToTop( ToTopFlags nFlags )
318 ImplCalcToTopData aStartData;
319 ImplCalcToTopData* pCurData;
320 ImplCalcToTopData* pNextData;
321 vcl::Window* pOverlapWindow;
322 if ( ImplIsOverlapWindow() )
323 pOverlapWindow = this;
324 else
325 pOverlapWindow = mpWindowImpl->mpOverlapWindow;
327 // first calculate paint areas
328 vcl::Window* pTempOverlapWindow = pOverlapWindow;
329 aStartData.mpNext = nullptr;
330 pCurData = &aStartData;
333 pTempOverlapWindow->ImplCalcToTop( pCurData );
334 if ( pCurData->mpNext )
335 pCurData = pCurData->mpNext;
336 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
338 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
339 // next calculate the paint areas of the ChildOverlap windows
340 pTempOverlapWindow = mpWindowImpl->mpFirstOverlap;
341 while ( pTempOverlapWindow )
343 pTempOverlapWindow->ImplCalcToTop( pCurData );
344 if ( pCurData->mpNext )
345 pCurData = pCurData->mpNext;
346 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext;
349 // and next change the windows list
350 pTempOverlapWindow = pOverlapWindow;
353 pTempOverlapWindow->ImplToTop( nFlags );
354 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
356 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
357 // as last step invalidate the invalid areas
358 pCurData = aStartData.mpNext;
359 while ( pCurData )
361 pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion, InvalidateFlags::Children );
362 pNextData = pCurData->mpNext;
363 delete pCurData->mpInvalidateRegion;
364 delete pCurData;
365 pCurData = pNextData;
369 void Window::ImplFocusToTop( ToTopFlags nFlags, bool bReallyVisible )
371 // do we need to fetch the focus?
372 if ( !(nFlags & ToTopFlags::NoGrabFocus) )
374 // first window with GrabFocus-Activate gets the focus
375 vcl::Window* pFocusWindow = this;
376 while ( !pFocusWindow->ImplIsOverlapWindow() )
378 // if the window has no BorderWindow, we
379 // should always find the belonging BorderWindow
380 if ( !pFocusWindow->mpWindowImpl->mpBorderWindow )
382 if ( pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus )
383 break;
385 pFocusWindow = pFocusWindow->ImplGetParent();
387 if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus) &&
388 !pFocusWindow->HasChildPathFocus( true ) )
389 pFocusWindow->GrabFocus();
392 if ( bReallyVisible )
393 ImplGenerateMouseMove();
396 void Window::ImplShowAllOverlaps()
398 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
399 while ( pOverlapWindow )
401 if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible )
403 pOverlapWindow->Show( true, ShowFlags::NoActivate );
404 pOverlapWindow->mpWindowImpl->mbOverlapVisible = false;
407 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
411 void Window::ImplHideAllOverlaps()
413 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
414 while ( pOverlapWindow )
416 if ( pOverlapWindow->IsVisible() )
418 pOverlapWindow->mpWindowImpl->mbOverlapVisible = true;
419 pOverlapWindow->Show( false );
422 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
426 void Window::ToTop( ToTopFlags nFlags )
428 if (!mpWindowImpl)
429 return;
431 ImplStartToTop( nFlags );
432 ImplFocusToTop( nFlags, IsReallyVisible() );
435 void Window::SetZOrder( vcl::Window* pRefWindow, ZOrderFlags nFlags )
438 if ( mpWindowImpl->mpBorderWindow )
440 mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags );
441 return;
444 if ( nFlags & ZOrderFlags::First )
446 if ( ImplIsOverlapWindow() )
447 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
448 else
449 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
450 nFlags |= ZOrderFlags::Before;
452 else if ( nFlags & ZOrderFlags::Last )
454 if ( ImplIsOverlapWindow() )
455 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
456 else
457 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
458 nFlags |= ZOrderFlags::Behind;
461 while ( pRefWindow && pRefWindow->mpWindowImpl->mpBorderWindow )
462 pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow;
463 if (!pRefWindow || pRefWindow == this || mpWindowImpl->mbFrame)
464 return;
466 SAL_WARN_IF( pRefWindow->mpWindowImpl->mpParent != mpWindowImpl->mpParent, "vcl", "Window::SetZOrder() - pRefWindow has other parent" );
467 if ( nFlags & ZOrderFlags::Before )
469 if ( pRefWindow->mpWindowImpl->mpPrev.get() == this )
470 return;
472 if ( ImplIsOverlapWindow() )
474 if ( mpWindowImpl->mpPrev )
475 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
476 else
477 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
478 if ( mpWindowImpl->mpNext )
479 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
480 else
481 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
482 if ( !pRefWindow->mpWindowImpl->mpPrev )
483 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
485 else
487 if ( mpWindowImpl->mpPrev )
488 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
489 else
490 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
491 if ( mpWindowImpl->mpNext )
492 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
493 else
494 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
495 if ( !pRefWindow->mpWindowImpl->mpPrev )
496 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
499 mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev;
500 mpWindowImpl->mpNext = pRefWindow;
501 if ( mpWindowImpl->mpPrev )
502 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
503 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
505 else if ( nFlags & ZOrderFlags::Behind )
507 if ( pRefWindow->mpWindowImpl->mpNext.get() == this )
508 return;
510 if ( ImplIsOverlapWindow() )
512 if ( mpWindowImpl->mpPrev )
513 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
514 else
515 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
516 if ( mpWindowImpl->mpNext )
517 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
518 else
519 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
520 if ( !pRefWindow->mpWindowImpl->mpNext )
521 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
523 else
525 if ( mpWindowImpl->mpPrev )
526 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
527 else
528 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
529 if ( mpWindowImpl->mpNext )
530 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
531 else
532 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
533 if ( !pRefWindow->mpWindowImpl->mpNext )
534 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
537 mpWindowImpl->mpPrev = pRefWindow;
538 mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext;
539 if ( mpWindowImpl->mpNext )
540 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
541 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
544 if ( IsReallyVisible() )
546 if ( mpWindowImpl->mbInitWinClipRegion || !mpWindowImpl->maWinClipRegion.IsEmpty() )
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 )
560 // Invalidate all windows which are next to each other
561 // Is INCOMPLETE !!!
562 Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
563 vcl::Window* pWindow = nullptr;
564 if ( ImplIsOverlapWindow() )
566 if ( mpWindowImpl->mpOverlapWindow )
567 pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
569 else
570 pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
571 // Invalidate all windows in front of us and which are covered by us
572 while ( pWindow )
574 if ( pWindow == this )
575 break;
576 Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
577 Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
578 if ( aWinRect.IsOver( 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 Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
590 Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
591 if ( aWinRect.IsOver( aCompRect ) )
593 Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
594 break;
597 pWindow = pWindow->mpWindowImpl->mpNext;
604 void Window::EnableAlwaysOnTop( bool bEnable )
607 mpWindowImpl->mbAlwaysOnTop = bEnable;
609 if ( mpWindowImpl->mpBorderWindow )
610 mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable );
611 else if ( bEnable && IsReallyVisible() )
612 ToTop();
614 if ( mpWindowImpl->mbFrame )
615 mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable );
618 bool Window::IsTopWindow() const
620 if ( !mpWindowImpl || mpWindowImpl->mbInDispose )
621 return false;
623 // topwindows must be frames or they must have a borderwindow which is a frame
624 if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) )
625 return false;
627 ImplGetWinData();
628 if( mpWindowImpl->mpWinData->mnIsTopWindow == (sal_uInt16)~0) // still uninitialized
630 // #113722#, cache result of expensive queryInterface call
631 vcl::Window *pThisWin = const_cast<vcl::Window*>(this);
632 uno::Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY );
633 pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0;
635 return mpWindowImpl->mpWinData->mnIsTopWindow == 1;
638 vcl::Window* Window::FindWindow( const Point& rPos ) const
641 Point aPos = OutputToScreenPixel( rPos );
642 return const_cast<vcl::Window*>(this)->ImplFindWindow( aPos );
645 vcl::Window* Window::ImplFindWindow( const Point& rFramePos )
647 vcl::Window* pTempWindow;
648 vcl::Window* pFindWindow;
650 // first check all overlapping windows
651 pTempWindow = mpWindowImpl->mpFirstOverlap;
652 while ( pTempWindow )
654 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
655 if ( pFindWindow )
656 return pFindWindow;
657 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
660 // then we check our window
661 if ( !mpWindowImpl->mbVisible )
662 return nullptr;
664 WindowHitTest nHitTest = ImplHitTest( rFramePos );
665 if ( nHitTest & WindowHitTest::Inside )
667 // and then we check all child windows
668 pTempWindow = mpWindowImpl->mpFirstChild;
669 while ( pTempWindow )
671 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
672 if ( pFindWindow )
673 return pFindWindow;
674 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
677 if ( nHitTest & WindowHitTest::Transparent )
678 return nullptr;
679 else
680 return this;
683 return nullptr;
686 bool Window::ImplIsRealParentPath( const vcl::Window* pWindow ) const
688 pWindow = pWindow->GetParent();
689 while ( pWindow )
691 if ( pWindow == this )
692 return true;
693 pWindow = pWindow->GetParent();
696 return false;
699 bool Window::ImplIsChild( const vcl::Window* pWindow, bool bSystemWindow ) const
703 if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
704 break;
706 pWindow = pWindow->ImplGetParent();
708 if ( pWindow == this )
709 return true;
711 while ( pWindow );
713 return false;
716 bool Window::ImplIsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
718 if ( this == pWindow )
719 return true;
720 return ImplIsChild( pWindow, bSystemWindow );
723 void Window::ImplResetReallyVisible()
725 bool bBecameReallyInvisible = mpWindowImpl->mbReallyVisible;
727 mbDevOutput = false;
728 mpWindowImpl->mbReallyVisible = false;
729 mpWindowImpl->mbReallyShown = false;
731 // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
732 // For this, the data member of the event must not be NULL.
733 // Previously, we did this in Window::Show, but there some events got lost in certain situations.
734 if( bBecameReallyInvisible && ImplIsAccessibleCandidate() )
735 CallEventListeners( VCLEVENT_WINDOW_HIDE, this );
736 // TODO. It's kind of a hack that we're re-using the VCLEVENT_WINDOW_HIDE. Normally, we should
737 // introduce another event which explicitly triggers the Accessibility implementations.
739 vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap;
740 while ( pWindow )
742 if ( pWindow->mpWindowImpl->mbReallyVisible )
743 pWindow->ImplResetReallyVisible();
744 pWindow = pWindow->mpWindowImpl->mpNext;
747 pWindow = mpWindowImpl->mpFirstChild;
748 while ( pWindow )
750 if ( pWindow->mpWindowImpl->mbReallyVisible )
751 pWindow->ImplResetReallyVisible();
752 pWindow = pWindow->mpWindowImpl->mpNext;
756 void Window::ImplUpdateWindowPtr( vcl::Window* pWindow )
758 if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
760 // release graphic
761 OutputDevice *pOutDev = GetOutDev();
762 pOutDev->ReleaseGraphics();
765 mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData;
766 mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame;
767 mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow;
768 if ( pWindow->ImplIsOverlapWindow() )
769 mpWindowImpl->mpOverlapWindow = pWindow;
770 else
771 mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow;
773 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
774 while ( pChild )
776 pChild->ImplUpdateWindowPtr( pWindow );
777 pChild = pChild->mpWindowImpl->mpNext;
781 void Window::ImplUpdateWindowPtr()
783 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
784 while ( pChild )
786 pChild->ImplUpdateWindowPtr( this );
787 pChild = pChild->mpWindowImpl->mpNext;
791 void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame )
793 bool bVisible = IsVisible();
794 Show( false );
795 ImplRemoveWindow( bNewFrame );
796 vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
797 ImplInsertWindow( ImplGetParent() );
798 mpWindowImpl->mpRealParent = pRealParent;
799 ImplUpdateWindowPtr();
800 if ( ImplUpdatePos() )
801 ImplUpdateSysObjPos();
803 if ( bNewFrame )
805 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
806 while ( pOverlapWindow )
808 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
809 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
810 pOverlapWindow = pNextOverlapWindow;
814 if ( bVisible )
815 Show();
818 SystemWindow* Window::GetSystemWindow() const
821 const vcl::Window* pWin = this;
822 while ( pWin && !pWin->IsSystemWindow() )
823 pWin = pWin->GetParent();
824 return static_cast<SystemWindow*>(const_cast<Window*>(pWin));
827 static SystemWindow *ImplGetLastSystemWindow( vcl::Window *pWin )
829 // get the most top-level system window, the one that contains the taskpanelist
830 SystemWindow *pSysWin = nullptr;
831 if( !pWin )
832 return pSysWin;
833 vcl::Window *pMyParent = pWin;
834 while ( pMyParent )
836 if ( pMyParent->IsSystemWindow() )
837 pSysWin = static_cast<SystemWindow*>(pMyParent);
838 pMyParent = pMyParent->GetParent();
840 return pSysWin;
843 void Window::SetParent( vcl::Window* pNewParent )
845 SAL_WARN_IF( !pNewParent, "vcl", "Window::SetParent(): pParent == NULL" );
846 SAL_WARN_IF( pNewParent == this, "vcl", "someone tried to reparent a window to itself" );
848 if( !pNewParent || pNewParent == this )
849 return;
851 // check if the taskpanelist would change and move the window pointer accordingly
852 SystemWindow *pSysWin = ImplGetLastSystemWindow(this);
853 SystemWindow *pNewSysWin = nullptr;
854 bool bChangeTaskPaneList = false;
855 if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) )
857 pNewSysWin = ImplGetLastSystemWindow( pNewParent );
858 if( pNewSysWin && pNewSysWin != pSysWin )
860 bChangeTaskPaneList = true;
861 pSysWin->GetTaskPaneList()->RemoveWindow( this );
864 // remove ownerdraw decorated windows from list in the top-most frame window
865 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
867 ::std::vector< VclPtr<vcl::Window> >& rList = ImplGetOwnerDrawList();
868 auto p = ::std::find( rList.begin(), rList.end(), VclPtr<vcl::Window>(this) );
869 if( p != rList.end() )
870 rList.erase( p );
873 ImplSetFrameParent( pNewParent );
875 if ( mpWindowImpl->mpBorderWindow )
877 mpWindowImpl->mpRealParent = pNewParent;
878 mpWindowImpl->mpBorderWindow->SetParent( pNewParent );
879 return;
882 if ( mpWindowImpl->mpParent.get() == pNewParent )
883 return;
885 if ( mpWindowImpl->mbFrame )
886 mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame );
888 bool bVisible = IsVisible();
889 Show( false, ShowFlags::NoFocusChange );
891 // check if the overlap window changes
892 vcl::Window* pOldOverlapWindow;
893 vcl::Window* pNewOverlapWindow = nullptr;
894 if ( ImplIsOverlapWindow() )
895 pOldOverlapWindow = nullptr;
896 else
898 pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow();
899 if ( mpWindowImpl->mpOverlapWindow.get() != pNewOverlapWindow )
900 pOldOverlapWindow = mpWindowImpl->mpOverlapWindow;
901 else
902 pOldOverlapWindow = nullptr;
905 // convert windows in the hierarchy
906 bool bFocusOverlapWin = HasChildPathFocus( true );
907 bool bFocusWin = HasChildPathFocus();
908 bool bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow;
909 if ( bNewFrame )
911 if ( mpWindowImpl->mpFrameData->mpFocusWin )
913 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) )
914 mpWindowImpl->mpFrameData->mpFocusWin = nullptr;
916 if ( mpWindowImpl->mpFrameData->mpMouseMoveWin )
918 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) )
919 mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr;
921 if ( mpWindowImpl->mpFrameData->mpMouseDownWin )
923 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) )
924 mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr;
927 ImplRemoveWindow( bNewFrame );
928 ImplInsertWindow( pNewParent );
929 if ( mpWindowImpl->mnParentClipMode & ParentClipMode::Clip )
930 pNewParent->mpWindowImpl->mbClipChildren = true;
931 ImplUpdateWindowPtr();
932 if ( ImplUpdatePos() )
933 ImplUpdateSysObjPos();
935 // If the Overlap-Window has changed, we need to test whether
936 // OverlapWindows that had the Child window as their parent
937 // need to be put into the window hierarchy.
938 if ( ImplIsOverlapWindow() )
940 if ( bNewFrame )
942 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
943 while ( pOverlapWindow )
945 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
946 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
947 pOverlapWindow = pNextOverlapWindow;
951 else if ( pOldOverlapWindow )
953 // reset Focus-Save
954 if ( bFocusWin ||
955 (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow &&
956 IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) )
957 pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
959 vcl::Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap;
960 while ( pOverlapWindow )
962 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
963 if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) )
964 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
965 pOverlapWindow = pNextOverlapWindow;
968 // update activate-status at next overlap window
969 if ( HasChildPathFocus( true ) )
970 ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
973 // also convert Activate-Status
974 if ( bNewFrame )
976 if ( (GetType() == WINDOW_BORDERWINDOW) &&
977 (ImplGetWindow()->GetType() == WINDOW_FLOATINGWINDOW) )
978 static_cast<ImplBorderWindow*>(this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus );
981 // when required give focus to new frame if
982 // FocusWindow is changed with SetParent()
983 if ( bFocusOverlapWin )
985 mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow();
986 if ( !mpWindowImpl->mpFrameData->mbHasFocus )
988 mpWindowImpl->mpFrame->ToTop( SalFrameToTop::NONE );
992 // Assure DragSource and DropTarget members are created
993 if ( bNewFrame )
995 GetDropTarget();
998 if( bChangeTaskPaneList )
999 pNewSysWin->GetTaskPaneList()->AddWindow( this );
1001 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
1002 ImplGetOwnerDrawList().push_back( this );
1004 if ( bVisible )
1005 Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
1008 bool Window::IsAncestorOf( const vcl::Window& rWindow ) const
1010 return ImplIsRealParentPath(&rWindow);
1013 sal_uInt16 Window::GetChildCount() const
1015 if (!mpWindowImpl)
1016 return 0;
1018 sal_uInt16 nChildCount = 0;
1019 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1020 while ( pChild )
1022 nChildCount++;
1023 pChild = pChild->mpWindowImpl->mpNext;
1026 return nChildCount;
1029 vcl::Window* Window::GetChild( sal_uInt16 nChild ) const
1031 if (!mpWindowImpl)
1032 return nullptr;
1034 sal_uInt16 nChildCount = 0;
1035 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1036 while ( pChild )
1038 if ( nChild == nChildCount )
1039 return pChild;
1040 pChild = pChild->mpWindowImpl->mpNext;
1041 nChildCount++;
1044 return nullptr;
1047 vcl::Window* Window::GetWindow( GetWindowType nType ) const
1049 if (!mpWindowImpl)
1050 return nullptr;
1052 switch ( nType )
1054 case GetWindowType::Parent:
1055 return mpWindowImpl->mpRealParent;
1057 case GetWindowType::FirstChild:
1058 return mpWindowImpl->mpFirstChild;
1060 case GetWindowType::LastChild:
1061 return mpWindowImpl->mpLastChild;
1063 case GetWindowType::Prev:
1064 return mpWindowImpl->mpPrev;
1066 case GetWindowType::Next:
1067 return mpWindowImpl->mpNext;
1069 case GetWindowType::FirstOverlap:
1070 return mpWindowImpl->mpFirstOverlap;
1072 case GetWindowType::LastOverlap:
1073 return mpWindowImpl->mpLastOverlap;
1075 case GetWindowType::Overlap:
1076 if ( ImplIsOverlapWindow() )
1077 return const_cast<vcl::Window*>(this);
1078 else
1079 return mpWindowImpl->mpOverlapWindow;
1081 case GetWindowType::ParentOverlap:
1082 if ( ImplIsOverlapWindow() )
1083 return mpWindowImpl->mpOverlapWindow;
1084 else
1085 return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow;
1087 case GetWindowType::Client:
1088 return const_cast<vcl::Window*>(this)->ImplGetWindow();
1090 case GetWindowType::RealParent:
1091 return ImplGetParent();
1093 case GetWindowType::Frame:
1094 return mpWindowImpl->mpFrameWindow;
1096 case GetWindowType::Border:
1097 if ( mpWindowImpl->mpBorderWindow )
1098 return mpWindowImpl->mpBorderWindow->GetWindow( GetWindowType::Border );
1099 return const_cast<vcl::Window*>(this);
1101 case GetWindowType::FirstTopWindowChild:
1102 return ImplGetWinData()->maTopWindowChildren.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren.begin()).get();
1104 case GetWindowType::LastTopWindowChild:
1105 return ImplGetWinData()->maTopWindowChildren.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren.rbegin()).get();
1107 case GetWindowType::PrevTopWindowSibling:
1109 if ( !mpWindowImpl->mpRealParent )
1110 return nullptr;
1111 const ::std::list< VclPtr<vcl::Window> >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
1112 ::std::list< VclPtr<vcl::Window> >::const_iterator myPos =
1113 ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
1114 if ( myPos == rTopWindows.end() )
1115 return nullptr;
1116 if ( myPos == rTopWindows.begin() )
1117 return nullptr;
1118 return *--myPos;
1121 case GetWindowType::NextTopWindowSibling:
1123 if ( !mpWindowImpl->mpRealParent )
1124 return nullptr;
1125 const ::std::list< VclPtr<vcl::Window> >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
1126 ::std::list< VclPtr<vcl::Window> >::const_iterator myPos =
1127 ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
1128 if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) )
1129 return nullptr;
1130 return *myPos;
1135 return nullptr;
1138 bool Window::IsChild( const vcl::Window* pWindow, bool bSystemWindow ) const
1142 if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
1143 break;
1145 pWindow = pWindow->ImplGetParent();
1147 if ( pWindow == this )
1148 return true;
1150 while ( pWindow );
1152 return false;
1155 bool Window::IsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
1158 if ( this == pWindow )
1159 return true;
1160 return ImplIsChild( pWindow, bSystemWindow );
1163 void Window::ImplSetFrameParent( const vcl::Window* pParent )
1165 vcl::Window* pFrameWindow = ImplGetSVData()->maWinData.mpFirstFrame;
1166 while( pFrameWindow )
1168 // search all frames that are children of this window
1169 // and reparent them
1170 if( ImplIsRealParentPath( pFrameWindow ) )
1172 SAL_WARN_IF( mpWindowImpl->mpFrame == pFrameWindow->mpWindowImpl->mpFrame, "vcl", "SetFrameParent to own" );
1173 SAL_WARN_IF( !mpWindowImpl->mpFrame, "vcl", "no frame" );
1174 SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : nullptr;
1175 pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame );
1177 pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1181 } /* namespace vcl */
1183 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */