nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / window / stacking.cxx
bloba23e3ff97f2aca71c17e1cb3379fae664702d581
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>
33 using namespace ::com::sun::star::uno;
34 using namespace ::com::sun::star::lang;
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()
52 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
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;
211 void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData )
213 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplCalcToTop(): Is not an OverlapWindow" );
215 if ( mpWindowImpl->mbFrame )
216 return;
218 if ( !IsReallyVisible() )
219 return;
221 // calculate region, where the window overlaps with other windows
222 Point aPoint( mnOutOffX, mnOutOffY );
223 vcl::Region aRegion( tools::Rectangle( aPoint,
224 Size( mnOutWidth, mnOutHeight ) ) );
225 vcl::Region aInvalidateRegion;
226 ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion );
228 if ( !aInvalidateRegion.IsEmpty() )
230 ImplCalcToTopData* pData = new ImplCalcToTopData;
231 pPrevData->mpNext.reset(pData);
232 pData->mpWindow = this;
233 pData->mpInvalidateRegion.reset(new vcl::Region( aInvalidateRegion ));
237 void Window::ImplToTop( ToTopFlags nFlags )
239 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplToTop(): Is not an OverlapWindow" );
241 if ( mpWindowImpl->mbFrame )
243 // on a mouse click in the external window, it is the latter's
244 // responsibility to assure our frame is put in front
245 if ( !mpWindowImpl->mpFrameData->mbHasFocus &&
246 !mpWindowImpl->mpFrameData->mbSysObjFocus &&
247 !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl &&
248 !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl )
250 // do not bring floating windows on the client to top
251 if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) )
253 SalFrameToTop nSysFlags = SalFrameToTop::NONE;
254 if ( nFlags & ToTopFlags::RestoreWhenMin )
255 nSysFlags |= SalFrameToTop::RestoreWhenMin;
256 if ( nFlags & ToTopFlags::ForegroundTask )
257 nSysFlags |= SalFrameToTop::ForegroundTask;
258 if ( nFlags & ToTopFlags::GrabFocusOnly )
259 nSysFlags |= SalFrameToTop::GrabFocusOnly;
260 mpWindowImpl->mpFrame->ToTop( nSysFlags );
264 else
266 if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap.get() != this )
268 // remove window from the list
269 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
270 if ( mpWindowImpl->mpNext )
271 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
272 else
273 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
275 // take AlwaysOnTop into account
276 bool bOnTop = IsAlwaysOnTopEnabled();
277 vcl::Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
278 if ( !bOnTop )
280 while ( pNextWin )
282 if ( !pNextWin->IsAlwaysOnTopEnabled() )
283 break;
284 pNextWin = pNextWin->mpWindowImpl->mpNext;
288 // add the window to the list again
289 mpWindowImpl->mpNext = pNextWin;
290 if ( pNextWin )
292 mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev;
293 pNextWin->mpWindowImpl->mpPrev = this;
295 else
297 mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
298 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
300 if ( mpWindowImpl->mpPrev )
301 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
302 else
303 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
305 // recalculate ClipRegion of this and all overlapping windows
306 if ( IsReallyVisible() )
308 mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows();
314 void Window::ImplStartToTop( ToTopFlags nFlags )
316 ImplCalcToTopData aStartData;
317 ImplCalcToTopData* pCurData;
318 vcl::Window* pOverlapWindow;
319 if ( ImplIsOverlapWindow() )
320 pOverlapWindow = this;
321 else
322 pOverlapWindow = mpWindowImpl->mpOverlapWindow;
324 // first calculate paint areas
325 vcl::Window* pTempOverlapWindow = pOverlapWindow;
326 aStartData.mpNext = nullptr;
327 pCurData = &aStartData;
330 pTempOverlapWindow->ImplCalcToTop( pCurData );
331 if ( pCurData->mpNext )
332 pCurData = pCurData->mpNext.get();
333 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
335 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
336 // next calculate the paint areas of the ChildOverlap windows
337 pTempOverlapWindow = mpWindowImpl->mpFirstOverlap;
338 while ( pTempOverlapWindow )
340 pTempOverlapWindow->ImplCalcToTop( pCurData );
341 if ( pCurData->mpNext )
342 pCurData = pCurData->mpNext.get();
343 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext;
346 // and next change the windows list
347 pTempOverlapWindow = pOverlapWindow;
350 pTempOverlapWindow->ImplToTop( nFlags );
351 pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow;
353 while ( !pTempOverlapWindow->mpWindowImpl->mbFrame );
354 // as last step invalidate the invalid areas
355 pCurData = aStartData.mpNext.get();
356 while ( pCurData )
358 pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion.get(), InvalidateFlags::Children );
359 pCurData = pCurData->mpNext.get();
363 void Window::ImplFocusToTop( ToTopFlags nFlags, bool bReallyVisible )
365 // do we need to fetch the focus?
366 if ( !(nFlags & ToTopFlags::NoGrabFocus) )
368 // first window with GrabFocus-Activate gets the focus
369 vcl::Window* pFocusWindow = this;
370 while ( !pFocusWindow->ImplIsOverlapWindow() )
372 // if the window has no BorderWindow, we
373 // should always find the belonging BorderWindow
374 if ( !pFocusWindow->mpWindowImpl->mpBorderWindow )
376 if ( pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus )
377 break;
379 pFocusWindow = pFocusWindow->ImplGetParent();
381 if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ActivateModeFlags::GrabFocus) &&
382 !pFocusWindow->HasChildPathFocus( true ) )
383 pFocusWindow->GrabFocus();
386 if ( bReallyVisible )
387 ImplGenerateMouseMove();
390 void Window::ImplShowAllOverlaps()
392 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
393 while ( pOverlapWindow )
395 if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible )
397 pOverlapWindow->Show( true, ShowFlags::NoActivate );
398 pOverlapWindow->mpWindowImpl->mbOverlapVisible = false;
401 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
405 void Window::ImplHideAllOverlaps()
407 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
408 while ( pOverlapWindow )
410 if ( pOverlapWindow->IsVisible() )
412 pOverlapWindow->mpWindowImpl->mbOverlapVisible = true;
413 pOverlapWindow->Show( false );
416 pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
420 void Window::ToTop( ToTopFlags nFlags )
422 if (!mpWindowImpl)
423 return;
425 ImplStartToTop( nFlags );
426 ImplFocusToTop( nFlags, IsReallyVisible() );
429 void Window::SetZOrder( vcl::Window* pRefWindow, ZOrderFlags nFlags )
432 if ( mpWindowImpl->mpBorderWindow )
434 mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags );
435 return;
438 if ( nFlags & ZOrderFlags::First )
440 if ( ImplIsOverlapWindow() )
441 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
442 else
443 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild;
444 nFlags |= ZOrderFlags::Before;
446 else if ( nFlags & ZOrderFlags::Last )
448 if ( ImplIsOverlapWindow() )
449 pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap;
450 else
451 pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild;
452 nFlags |= ZOrderFlags::Behind;
455 while ( pRefWindow && pRefWindow->mpWindowImpl->mpBorderWindow )
456 pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow;
457 if (!pRefWindow || pRefWindow == this || mpWindowImpl->mbFrame)
458 return;
460 SAL_WARN_IF( pRefWindow->mpWindowImpl->mpParent != mpWindowImpl->mpParent, "vcl", "Window::SetZOrder() - pRefWindow has other parent" );
461 if ( nFlags & ZOrderFlags::Before )
463 if ( pRefWindow->mpWindowImpl->mpPrev.get() == this )
464 return;
466 if ( ImplIsOverlapWindow() )
468 if ( mpWindowImpl->mpPrev )
469 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
470 else
471 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
472 if ( mpWindowImpl->mpNext )
473 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
474 else
475 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
476 if ( !pRefWindow->mpWindowImpl->mpPrev )
477 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this;
479 else
481 if ( mpWindowImpl->mpPrev )
482 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
483 else
484 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
485 if ( mpWindowImpl->mpNext )
486 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
487 else
488 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
489 if ( !pRefWindow->mpWindowImpl->mpPrev )
490 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this;
493 mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev;
494 mpWindowImpl->mpNext = pRefWindow;
495 if ( mpWindowImpl->mpPrev )
496 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
497 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
499 else if ( nFlags & ZOrderFlags::Behind )
501 if ( pRefWindow->mpWindowImpl->mpNext.get() == this )
502 return;
504 if ( ImplIsOverlapWindow() )
506 if ( mpWindowImpl->mpPrev )
507 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
508 else
509 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext;
510 if ( mpWindowImpl->mpNext )
511 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
512 else
513 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev;
514 if ( !pRefWindow->mpWindowImpl->mpNext )
515 mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this;
517 else
519 if ( mpWindowImpl->mpPrev )
520 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext;
521 else
522 mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext;
523 if ( mpWindowImpl->mpNext )
524 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev;
525 else
526 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev;
527 if ( !pRefWindow->mpWindowImpl->mpNext )
528 mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this;
531 mpWindowImpl->mpPrev = pRefWindow;
532 mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext;
533 if ( mpWindowImpl->mpNext )
534 mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this;
535 mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this;
538 if ( !IsReallyVisible() )
539 return;
541 if ( !mpWindowImpl->mbInitWinClipRegion && mpWindowImpl->maWinClipRegion.IsEmpty() )
542 return;
544 bool bInitWinClipRegion = mpWindowImpl->mbInitWinClipRegion;
545 ImplSetClipFlag();
547 // When ClipRegion was not initialised, assume
548 // the window has not been sent, therefore do not
549 // trigger any Invalidates. This is an optimization
550 // for HTML documents with many controls. If this
551 // check gives problems, a flag should be introduced
552 // which tracks whether the window has already been
553 // emitted after Show
554 if ( bInitWinClipRegion )
555 return;
557 // Invalidate all windows which are next to each other
558 // Is INCOMPLETE !!!
559 tools::Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
560 vcl::Window* pWindow = nullptr;
561 if ( ImplIsOverlapWindow() )
563 if ( mpWindowImpl->mpOverlapWindow )
564 pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap;
566 else
567 pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild;
568 // Invalidate all windows in front of us and which are covered by us
569 while ( pWindow )
571 if ( pWindow == this )
572 break;
573 tools::Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
574 Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
575 if ( aWinRect.IsOver( aCompRect ) )
576 pWindow->Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
577 pWindow = pWindow->mpWindowImpl->mpNext;
580 // If we are covered by a window in the background
581 // we should redraw it
582 while ( pWindow )
584 if ( pWindow != this )
586 tools::Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ),
587 Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) );
588 if ( aWinRect.IsOver( aCompRect ) )
590 Invalidate( InvalidateFlags::Children | InvalidateFlags::NoTransparent );
591 break;
594 pWindow = pWindow->mpWindowImpl->mpNext;
598 void Window::EnableAlwaysOnTop( bool bEnable )
601 mpWindowImpl->mbAlwaysOnTop = bEnable;
603 if ( mpWindowImpl->mpBorderWindow )
604 mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable );
605 else if ( bEnable && IsReallyVisible() )
606 ToTop();
608 if ( mpWindowImpl->mbFrame )
609 mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable );
612 bool Window::IsTopWindow() const
614 if ( !mpWindowImpl || mpWindowImpl->mbInDispose )
615 return false;
617 // topwindows must be frames or they must have a borderwindow which is a frame
618 if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) )
619 return false;
621 ImplGetWinData();
622 if( mpWindowImpl->mpWinData->mnIsTopWindow == sal_uInt16(~0)) // still uninitialized
624 // #113722#, cache result of expensive queryInterface call
625 vcl::Window *pThisWin = const_cast<vcl::Window*>(this);
626 uno::Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY );
627 pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0;
629 return mpWindowImpl->mpWinData->mnIsTopWindow == 1;
632 vcl::Window* Window::ImplFindWindow( const Point& rFramePos )
634 vcl::Window* pTempWindow;
635 vcl::Window* pFindWindow;
637 // first check all overlapping windows
638 pTempWindow = mpWindowImpl->mpFirstOverlap;
639 while ( pTempWindow )
641 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
642 if ( pFindWindow )
643 return pFindWindow;
644 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
647 // then we check our window
648 if ( !mpWindowImpl->mbVisible )
649 return nullptr;
651 WindowHitTest nHitTest = ImplHitTest( rFramePos );
652 if ( nHitTest & WindowHitTest::Inside )
654 // and then we check all child windows
655 pTempWindow = mpWindowImpl->mpFirstChild;
656 while ( pTempWindow )
658 pFindWindow = pTempWindow->ImplFindWindow( rFramePos );
659 if ( pFindWindow )
660 return pFindWindow;
661 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
664 if ( nHitTest & WindowHitTest::Transparent )
665 return nullptr;
666 else
667 return this;
670 return nullptr;
673 bool Window::ImplIsRealParentPath( const vcl::Window* pWindow ) const
675 pWindow = pWindow->GetParent();
676 while ( pWindow )
678 if ( pWindow == this )
679 return true;
680 pWindow = pWindow->GetParent();
683 return false;
686 bool Window::ImplIsChild( const vcl::Window* pWindow, bool bSystemWindow ) const
690 if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() )
691 break;
693 pWindow = pWindow->ImplGetParent();
695 if ( pWindow == this )
696 return true;
698 while ( pWindow );
700 return false;
703 bool Window::ImplIsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
705 if ( this == pWindow )
706 return true;
707 return ImplIsChild( pWindow, bSystemWindow );
710 void Window::ImplResetReallyVisible()
712 bool bBecameReallyInvisible = mpWindowImpl->mbReallyVisible;
714 mbDevOutput = false;
715 mpWindowImpl->mbReallyVisible = false;
716 mpWindowImpl->mbReallyShown = false;
718 // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
719 // For this, the data member of the event must not be NULL.
720 // Previously, we did this in Window::Show, but there some events got lost in certain situations.
721 if( bBecameReallyInvisible && ImplIsAccessibleCandidate() )
722 CallEventListeners( VclEventId::WindowHide, this );
723 // TODO. It's kind of a hack that we're re-using the VclEventId::WindowHide. Normally, we should
724 // introduce another event which explicitly triggers the Accessibility implementations.
726 vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap;
727 while ( pWindow )
729 if ( pWindow->mpWindowImpl->mbReallyVisible )
730 pWindow->ImplResetReallyVisible();
731 pWindow = pWindow->mpWindowImpl->mpNext;
734 pWindow = mpWindowImpl->mpFirstChild;
735 while ( pWindow )
737 if ( pWindow->mpWindowImpl->mbReallyVisible )
738 pWindow->ImplResetReallyVisible();
739 pWindow = pWindow->mpWindowImpl->mpNext;
743 void Window::ImplUpdateWindowPtr( vcl::Window* pWindow )
745 if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow )
747 // release graphic
748 OutputDevice *pOutDev = GetOutDev();
749 pOutDev->ReleaseGraphics();
752 mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData;
753 if (mpWindowImpl->mpFrame != pWindow->mpWindowImpl->mpFrame)
755 mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame;
756 if (mpWindowImpl->mpSysObj)
757 mpWindowImpl->mpSysObj->Reparent(mpWindowImpl->mpFrame);
759 mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow;
760 if ( pWindow->ImplIsOverlapWindow() )
761 mpWindowImpl->mpOverlapWindow = pWindow;
762 else
763 mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow;
765 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
766 while ( pChild )
768 pChild->ImplUpdateWindowPtr( pWindow );
769 pChild = pChild->mpWindowImpl->mpNext;
773 void Window::ImplUpdateWindowPtr()
775 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
776 while ( pChild )
778 pChild->ImplUpdateWindowPtr( this );
779 pChild = pChild->mpWindowImpl->mpNext;
783 void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame )
785 bool bVisible = IsVisible();
786 Show( false );
787 ImplRemoveWindow( bNewFrame );
788 vcl::Window* pRealParent = mpWindowImpl->mpRealParent;
789 ImplInsertWindow( ImplGetParent() );
790 mpWindowImpl->mpRealParent = pRealParent;
791 ImplUpdateWindowPtr();
792 if ( ImplUpdatePos() )
793 ImplUpdateSysObjPos();
795 if ( bNewFrame )
797 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
798 while ( pOverlapWindow )
800 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
801 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
802 pOverlapWindow = pNextOverlapWindow;
806 if ( bVisible )
807 Show();
810 SystemWindow* Window::GetSystemWindow() const
813 const vcl::Window* pWin = this;
814 while ( pWin && !pWin->IsSystemWindow() )
815 pWin = pWin->GetParent();
816 return static_cast<SystemWindow*>(const_cast<Window*>(pWin));
819 static SystemWindow *ImplGetLastSystemWindow( vcl::Window *pWin )
821 // get the most top-level system window, the one that contains the taskpanelist
822 SystemWindow *pSysWin = nullptr;
823 if( !pWin )
824 return pSysWin;
825 vcl::Window *pMyParent = pWin;
826 while ( pMyParent )
828 if ( pMyParent->IsSystemWindow() )
829 pSysWin = static_cast<SystemWindow*>(pMyParent);
830 pMyParent = pMyParent->GetParent();
832 return pSysWin;
835 void Window::SetParent( vcl::Window* pNewParent )
837 SAL_WARN_IF( !pNewParent, "vcl", "Window::SetParent(): pParent == NULL" );
838 SAL_WARN_IF( pNewParent == this, "vcl", "someone tried to reparent a window to itself" );
840 if( !pNewParent || pNewParent == this )
841 return;
843 // check if the taskpanelist would change and move the window pointer accordingly
844 SystemWindow *pSysWin = ImplGetLastSystemWindow(this);
845 SystemWindow *pNewSysWin = nullptr;
846 bool bChangeTaskPaneList = false;
847 if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) )
849 pNewSysWin = ImplGetLastSystemWindow( pNewParent );
850 if( pNewSysWin && pNewSysWin != pSysWin )
852 bChangeTaskPaneList = true;
853 pSysWin->GetTaskPaneList()->RemoveWindow( this );
856 // remove ownerdraw decorated windows from list in the top-most frame window
857 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
859 ::std::vector< VclPtr<vcl::Window> >& rList = ImplGetOwnerDrawList();
860 auto p = ::std::find( rList.begin(), rList.end(), VclPtr<vcl::Window>(this) );
861 if( p != rList.end() )
862 rList.erase( p );
865 ImplSetFrameParent( pNewParent );
867 if ( mpWindowImpl->mpBorderWindow )
869 mpWindowImpl->mpRealParent = pNewParent;
870 mpWindowImpl->mpBorderWindow->SetParent( pNewParent );
871 return;
874 if ( mpWindowImpl->mpParent.get() == pNewParent )
875 return;
877 if ( mpWindowImpl->mbFrame )
878 mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame );
880 bool bVisible = IsVisible();
881 Show( false, ShowFlags::NoFocusChange );
883 // check if the overlap window changes
884 vcl::Window* pOldOverlapWindow;
885 vcl::Window* pNewOverlapWindow = nullptr;
886 if ( ImplIsOverlapWindow() )
887 pOldOverlapWindow = nullptr;
888 else
890 pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow();
891 if ( mpWindowImpl->mpOverlapWindow.get() != pNewOverlapWindow )
892 pOldOverlapWindow = mpWindowImpl->mpOverlapWindow;
893 else
894 pOldOverlapWindow = nullptr;
897 // convert windows in the hierarchy
898 bool bFocusOverlapWin = HasChildPathFocus( true );
899 bool bFocusWin = HasChildPathFocus();
900 bool bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow;
901 if ( bNewFrame )
903 if ( mpWindowImpl->mpFrameData->mpFocusWin )
905 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) )
906 mpWindowImpl->mpFrameData->mpFocusWin = nullptr;
908 if ( mpWindowImpl->mpFrameData->mpMouseMoveWin )
910 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) )
911 mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr;
913 if ( mpWindowImpl->mpFrameData->mpMouseDownWin )
915 if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) )
916 mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr;
919 ImplRemoveWindow( bNewFrame );
920 ImplInsertWindow( pNewParent );
921 if ( mpWindowImpl->mnParentClipMode & ParentClipMode::Clip )
922 pNewParent->mpWindowImpl->mbClipChildren = true;
923 ImplUpdateWindowPtr();
924 if ( ImplUpdatePos() )
925 ImplUpdateSysObjPos();
927 // If the Overlap-Window has changed, we need to test whether
928 // OverlapWindows that had the Child window as their parent
929 // need to be put into the window hierarchy.
930 if ( ImplIsOverlapWindow() )
932 if ( bNewFrame )
934 vcl::Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap;
935 while ( pOverlapWindow )
937 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
938 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
939 pOverlapWindow = pNextOverlapWindow;
943 else if ( pOldOverlapWindow )
945 // reset Focus-Save
946 if ( bFocusWin ||
947 (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow &&
948 IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) )
949 pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
951 vcl::Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap;
952 while ( pOverlapWindow )
954 vcl::Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext;
955 if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) )
956 pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame );
957 pOverlapWindow = pNextOverlapWindow;
960 // update activate-status at next overlap window
961 if ( HasChildPathFocus( true ) )
962 ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow );
965 // also convert Activate-Status
966 if ( bNewFrame )
968 if ( (GetType() == WindowType::BORDERWINDOW) &&
969 (ImplGetWindow()->GetType() == WindowType::FLOATINGWINDOW) )
970 static_cast<ImplBorderWindow*>(this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus );
973 // when required give focus to new frame if
974 // FocusWindow is changed with SetParent()
975 if ( bFocusOverlapWin )
977 mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow();
978 if ( !mpWindowImpl->mpFrameData->mbHasFocus )
980 mpWindowImpl->mpFrame->ToTop( SalFrameToTop::NONE );
984 // Assure DragSource and DropTarget members are created
985 if ( bNewFrame )
987 GetDropTarget();
990 if( bChangeTaskPaneList )
991 pNewSysWin->GetTaskPaneList()->AddWindow( this );
993 if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame )
994 ImplGetOwnerDrawList().emplace_back(this );
996 if ( bVisible )
997 Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
1000 bool Window::IsAncestorOf( const vcl::Window& rWindow ) const
1002 return ImplIsRealParentPath(&rWindow);
1005 sal_uInt16 Window::GetChildCount() const
1007 if (!mpWindowImpl)
1008 return 0;
1010 sal_uInt16 nChildCount = 0;
1011 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1012 while ( pChild )
1014 nChildCount++;
1015 pChild = pChild->mpWindowImpl->mpNext;
1018 return nChildCount;
1021 vcl::Window* Window::GetChild( sal_uInt16 nChild ) const
1023 if (!mpWindowImpl)
1024 return nullptr;
1026 sal_uInt16 nChildCount = 0;
1027 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
1028 while ( pChild )
1030 if ( nChild == nChildCount )
1031 return pChild;
1032 pChild = pChild->mpWindowImpl->mpNext;
1033 nChildCount++;
1036 return nullptr;
1039 vcl::Window* Window::GetWindow( GetWindowType nType ) const
1041 if (!mpWindowImpl)
1042 return nullptr;
1044 switch ( nType )
1046 case GetWindowType::Parent:
1047 return mpWindowImpl->mpRealParent;
1049 case GetWindowType::FirstChild:
1050 return mpWindowImpl->mpFirstChild;
1052 case GetWindowType::LastChild:
1053 return mpWindowImpl->mpLastChild;
1055 case GetWindowType::Prev:
1056 return mpWindowImpl->mpPrev;
1058 case GetWindowType::Next:
1059 return mpWindowImpl->mpNext;
1061 case GetWindowType::FirstOverlap:
1062 return mpWindowImpl->mpFirstOverlap;
1064 case GetWindowType::Overlap:
1065 if ( ImplIsOverlapWindow() )
1066 return const_cast<vcl::Window*>(this);
1067 else
1068 return mpWindowImpl->mpOverlapWindow;
1070 case GetWindowType::ParentOverlap:
1071 if ( ImplIsOverlapWindow() )
1072 return mpWindowImpl->mpOverlapWindow;
1073 else
1074 return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow;
1076 case GetWindowType::Client:
1077 return this->ImplGetWindow();
1079 case GetWindowType::RealParent:
1080 return ImplGetParent();
1082 case GetWindowType::Frame:
1083 return mpWindowImpl->mpFrameWindow;
1085 case GetWindowType::Border:
1086 if ( mpWindowImpl->mpBorderWindow )
1087 return mpWindowImpl->mpBorderWindow->GetWindow( GetWindowType::Border );
1088 return const_cast<vcl::Window*>(this);
1090 case GetWindowType::FirstTopWindowChild:
1091 return ImplGetWinData()->maTopWindowChildren.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren.begin()).get();
1093 case GetWindowType::NextTopWindowSibling:
1095 if ( !mpWindowImpl->mpRealParent )
1096 return nullptr;
1097 const ::std::list< VclPtr<vcl::Window> >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren );
1098 ::std::list< VclPtr<vcl::Window> >::const_iterator myPos =
1099 ::std::find( rTopWindows.begin(), rTopWindows.end(), this );
1100 if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) )
1101 return nullptr;
1102 return *myPos;
1107 return nullptr;
1110 bool Window::IsChild( const vcl::Window* pWindow ) const
1114 if ( pWindow->ImplIsOverlapWindow() )
1115 break;
1117 pWindow = pWindow->ImplGetParent();
1119 if ( pWindow == this )
1120 return true;
1122 while ( pWindow );
1124 return false;
1127 bool Window::IsWindowOrChild( const vcl::Window* pWindow, bool bSystemWindow ) const
1130 if ( this == pWindow )
1131 return true;
1132 return ImplIsChild( pWindow, bSystemWindow );
1135 void Window::ImplSetFrameParent( const vcl::Window* pParent )
1137 vcl::Window* pFrameWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
1138 while( pFrameWindow )
1140 // search all frames that are children of this window
1141 // and reparent them
1142 if( ImplIsRealParentPath( pFrameWindow ) )
1144 SAL_WARN_IF( mpWindowImpl->mpFrame == pFrameWindow->mpWindowImpl->mpFrame, "vcl", "SetFrameParent to own" );
1145 SAL_WARN_IF( !mpWindowImpl->mpFrame, "vcl", "no frame" );
1146 SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : nullptr;
1147 pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame );
1149 pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1153 } /* namespace vcl */
1155 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */