1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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
)
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;
96 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= this;
100 if ( pParent
->ImplIsOverlapWindow() )
101 mpWindowImpl
->mpOverlapWindow
= pParent
;
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;
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
;
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
;
133 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= mpWindowImpl
->mpNext
;
134 if ( mpWindowImpl
->mpNext
)
135 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
137 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
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
;
169 if (nChildCount
== nNewPosition
)
171 pSource
= pSource
->mpWindowImpl
->mpNext
;
175 if (pSource
== this) //already at the right place
178 ImplRemoveWindow(false);
182 mpWindowImpl
->mpNext
= pSource
;
183 mpWindowImpl
->mpPrev
= pSource
->mpWindowImpl
->mpPrev
;
184 pSource
->mpWindowImpl
->mpPrev
= this;
187 mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
= this;
189 if (mpWindowImpl
->mpPrev
)
190 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
192 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= this;
195 void Window::ImplToBottomChild()
197 if ( ImplIsOverlapWindow() || mpWindowImpl
->mbReallyVisible
|| (mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
.get() == this) )
200 // put the window to the end of the list
201 if ( mpWindowImpl
->mpPrev
)
202 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
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
)
219 if ( !IsReallyVisible() )
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
);
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
;
272 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
274 // take AlwaysOnTop into account
275 bool bOnTop
= IsAlwaysOnTopEnabled();
276 vcl::Window
* pNextWin
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
281 if ( !pNextWin
->IsAlwaysOnTopEnabled() )
283 pNextWin
= pNextWin
->mpWindowImpl
->mpNext
;
287 // add the window to the list again
288 mpWindowImpl
->mpNext
= pNextWin
;
291 mpWindowImpl
->mpPrev
= pNextWin
->mpWindowImpl
->mpPrev
;
292 pNextWin
->mpWindowImpl
->mpPrev
= this;
296 mpWindowImpl
->mpPrev
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
;
297 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= this;
299 if ( mpWindowImpl
->mpPrev
)
300 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
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;
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();
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
)
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
)
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
);
437 if ( nFlags
& ZOrderFlags::First
)
439 if ( ImplIsOverlapWindow() )
440 pRefWindow
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
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
;
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
)
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 )
465 if ( ImplIsOverlapWindow() )
467 if ( mpWindowImpl
->mpPrev
)
468 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
470 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= mpWindowImpl
->mpNext
;
471 if ( mpWindowImpl
->mpNext
)
472 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
474 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
475 if ( !pRefWindow
->mpWindowImpl
->mpPrev
)
476 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= this;
480 if ( mpWindowImpl
->mpPrev
)
481 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
483 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= mpWindowImpl
->mpNext
;
484 if ( mpWindowImpl
->mpNext
)
485 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
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 )
503 if ( ImplIsOverlapWindow() )
505 if ( mpWindowImpl
->mpPrev
)
506 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
508 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= mpWindowImpl
->mpNext
;
509 if ( mpWindowImpl
->mpNext
)
510 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
512 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
513 if ( !pRefWindow
->mpWindowImpl
->mpNext
)
514 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= this;
518 if ( mpWindowImpl
->mpPrev
)
519 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
521 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= mpWindowImpl
->mpNext
;
522 if ( mpWindowImpl
->mpNext
)
523 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
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() )
540 if ( !mpWindowImpl
->mbInitWinClipRegion
&& mpWindowImpl
->maWinClipRegion
.IsEmpty() )
543 bool bInitWinClipRegion
= mpWindowImpl
->mbInitWinClipRegion
;
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
)
556 // Invalidate all windows which are next to each other
558 tools::Rectangle aWinRect
= GetOutputRectPixel();
559 vcl::Window
* pWindow
= nullptr;
560 if ( ImplIsOverlapWindow() )
562 if ( mpWindowImpl
->mpOverlapWindow
)
563 pWindow
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
566 pWindow
= ImplGetParent()->mpWindowImpl
->mpFirstChild
;
567 // Invalidate all windows in front of us and which are covered by us
570 if ( pWindow
== this )
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
582 if ( pWindow
!= this )
584 tools::Rectangle aCompRect
= pWindow
->GetOutputRectPixel();
585 if ( aWinRect
.Overlaps( aCompRect
) )
587 Invalidate( InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
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() )
605 if ( mpWindowImpl
->mbFrame
)
606 mpWindowImpl
->mpFrame
->SetAlwaysOnTop( bEnable
);
609 bool Window::IsTopWindow() const
611 if ( !mpWindowImpl
|| mpWindowImpl
->mbInDispose
)
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
) )
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
);
641 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
644 // then we check our window
645 if ( !mpWindowImpl
->mbVisible
)
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
);
658 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
661 if ( nHitTest
& WindowHitTest::Transparent
)
670 bool Window::ImplIsRealParentPath( const vcl::Window
* pWindow
) const
672 pWindow
= pWindow
->GetParent();
675 if ( pWindow
== this )
677 pWindow
= pWindow
->GetParent();
683 bool Window::ImplIsChild( const vcl::Window
* pWindow
, bool bSystemWindow
) const
687 if ( !bSystemWindow
&& pWindow
->ImplIsOverlapWindow() )
690 pWindow
= pWindow
->ImplGetParent();
692 if ( pWindow
== this )
700 bool Window::ImplIsWindowOrChild( const vcl::Window
* pWindow
, bool bSystemWindow
) const
702 if ( this == pWindow
)
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
;
726 if ( pWindow
->mpWindowImpl
->mbReallyVisible
)
727 pWindow
->ImplResetReallyVisible();
728 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
731 pWindow
= mpWindowImpl
->mpFirstChild
;
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
)
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
;
760 mpWindowImpl
->mpOverlapWindow
= pWindow
->mpWindowImpl
->mpOverlapWindow
;
762 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
765 pChild
->ImplUpdateWindowPtr( pWindow
);
766 pChild
= pChild
->mpWindowImpl
->mpNext
;
770 void Window::ImplUpdateWindowPtr()
772 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
775 pChild
->ImplUpdateWindowPtr( this );
776 pChild
= pChild
->mpWindowImpl
->mpNext
;
780 void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame
)
782 bool bVisible
= IsVisible();
784 ImplRemoveWindow( bNewFrame
);
785 vcl::Window
* pRealParent
= mpWindowImpl
->mpRealParent
;
786 ImplInsertWindow( ImplGetParent() );
787 mpWindowImpl
->mpRealParent
= pRealParent
;
788 ImplUpdateWindowPtr();
789 if ( ImplUpdatePos() )
790 ImplUpdateSysObjPos();
794 vcl::Window
* pOverlapWindow
= mpWindowImpl
->mpFirstOverlap
;
795 while ( pOverlapWindow
)
797 vcl::Window
* pNextOverlapWindow
= pOverlapWindow
->mpWindowImpl
->mpNext
;
798 pOverlapWindow
->ImplUpdateOverlapWindowPtr( bNewFrame
);
799 pOverlapWindow
= pNextOverlapWindow
;
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;
822 vcl::Window
*pMyParent
= pWin
;
825 if ( pMyParent
->IsSystemWindow() )
826 pSysWin
= static_cast<SystemWindow
*>(pMyParent
);
827 pMyParent
= pMyParent
->GetParent();
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 )
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() )
862 ImplSetFrameParent( pNewParent
);
864 if ( mpWindowImpl
->mpBorderWindow
)
866 mpWindowImpl
->mpRealParent
= pNewParent
;
867 mpWindowImpl
->mpBorderWindow
->SetParent( pNewParent
);
871 if ( mpWindowImpl
->mpParent
.get() == pNewParent
)
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;
887 pNewOverlapWindow
= pNewParent
->ImplGetFirstOverlapWindow();
888 if ( mpWindowImpl
->mpOverlapWindow
.get() != pNewOverlapWindow
)
889 pOldOverlapWindow
= mpWindowImpl
->mpOverlapWindow
;
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
;
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() )
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
)
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
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
987 if( bChangeTaskPaneList
)
988 pNewSysWin
->GetTaskPaneList()->AddWindow( this );
990 if( (GetStyle() & WB_OWNERDRAWDECORATION
) && mpWindowImpl
->mbFrame
)
991 ImplGetOwnerDrawList().emplace_back(this );
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
1007 sal_uInt16 nChildCount
= 0;
1008 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
1012 pChild
= pChild
->mpWindowImpl
->mpNext
;
1018 vcl::Window
* Window::GetChild( sal_uInt16 nChild
) const
1023 sal_uInt16 nChildCount
= 0;
1024 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
1027 if ( nChild
== nChildCount
)
1029 pChild
= pChild
->mpWindowImpl
->mpNext
;
1036 vcl::Window
* Window::GetWindow( GetWindowType nType
) const
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);
1065 return mpWindowImpl
->mpOverlapWindow
;
1067 case GetWindowType::ParentOverlap
:
1068 if ( ImplIsOverlapWindow() )
1069 return mpWindowImpl
->mpOverlapWindow
;
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
)
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() ) )
1107 bool Window::IsChild( const vcl::Window
* pWindow
) const
1111 if ( pWindow
->ImplIsOverlapWindow() )
1114 pWindow
= pWindow
->ImplGetParent();
1116 if ( pWindow
== this )
1124 bool Window::IsWindowOrChild( const vcl::Window
* pWindow
, bool bSystemWindow
) const
1127 if ( this == pWindow
)
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: */