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::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
;
50 vcl::Window
* Window::ImplGetTopmostFrameWindow() const
52 const vcl::Window
*pTopmostParent
= this;
53 while( pTopmostParent
->ImplGetParent() )
54 pTopmostParent
= pTopmostParent
->ImplGetParent();
55 return pTopmostParent
->mpWindowImpl
->mpFrameWindow
;
58 void Window::ImplInsertWindow( vcl::Window
* pParent
)
60 mpWindowImpl
->mpParent
= pParent
;
61 mpWindowImpl
->mpRealParent
= pParent
;
63 if ( !pParent
|| mpWindowImpl
->mbFrame
)
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;
95 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= this;
99 if ( pParent
->ImplIsOverlapWindow() )
100 mpWindowImpl
->mpOverlapWindow
= pParent
;
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;
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
;
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
;
132 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= mpWindowImpl
->mpNext
;
133 if ( mpWindowImpl
->mpNext
)
134 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
136 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
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
;
168 if (nChildCount
== nNewPosition
)
170 pSource
= pSource
->mpWindowImpl
->mpNext
;
174 if (pSource
== this) //already at the right place
177 ImplRemoveWindow(false);
181 mpWindowImpl
->mpNext
= pSource
;
182 mpWindowImpl
->mpPrev
= pSource
->mpWindowImpl
->mpPrev
;
183 pSource
->mpWindowImpl
->mpPrev
= this;
186 mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
= this;
188 if (mpWindowImpl
->mpPrev
)
189 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
191 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= this;
194 void Window::ImplToBottomChild()
196 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
;
204 // coverity[copy_paste_error : FALSE] - this is correct mpFirstChild, not mpNext
205 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= mpWindowImpl
->mpNext
;
207 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
208 mpWindowImpl
->mpPrev
= mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
;
209 mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
= this;
210 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
211 mpWindowImpl
->mpNext
= nullptr;
214 void Window::ImplCalcToTop( ImplCalcToTopData
* pPrevData
)
216 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplCalcToTop(): Is not an OverlapWindow" );
218 if ( mpWindowImpl
->mbFrame
)
221 if ( !IsReallyVisible() )
224 // calculate region, where the window overlaps with other windows
225 vcl::Region
aRegion( GetOutputRectPixel() );
226 vcl::Region aInvalidateRegion
;
227 ImplCalcOverlapRegionOverlaps( aRegion
, aInvalidateRegion
);
229 if ( !aInvalidateRegion
.IsEmpty() )
231 ImplCalcToTopData
* pData
= new ImplCalcToTopData
;
232 pPrevData
->mpNext
.reset(pData
);
233 pData
->mpWindow
= this;
234 pData
->mpInvalidateRegion
.reset(new vcl::Region(std::move(aInvalidateRegion
)));
238 void Window::ImplToTop( ToTopFlags nFlags
)
240 SAL_WARN_IF( !ImplIsOverlapWindow(), "vcl", "Window::ImplToTop(): Is not an OverlapWindow" );
242 if ( mpWindowImpl
->mbFrame
)
244 // on a mouse click in the external window, it is the latter's
245 // responsibility to assure our frame is put in front
246 if ( !mpWindowImpl
->mpFrameData
->mbHasFocus
&&
247 !mpWindowImpl
->mpFrameData
->mbSysObjFocus
&&
248 !mpWindowImpl
->mpFrameData
->mbInSysObjFocusHdl
&&
249 !mpWindowImpl
->mpFrameData
->mbInSysObjToTopHdl
)
251 // do not bring floating windows on the client to top
252 if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN
) )
254 SalFrameToTop nSysFlags
= SalFrameToTop::NONE
;
255 if ( nFlags
& ToTopFlags::RestoreWhenMin
)
256 nSysFlags
|= SalFrameToTop::RestoreWhenMin
;
257 if ( nFlags
& ToTopFlags::ForegroundTask
)
258 nSysFlags
|= SalFrameToTop::ForegroundTask
;
259 if ( nFlags
& ToTopFlags::GrabFocusOnly
)
260 nSysFlags
|= SalFrameToTop::GrabFocusOnly
;
261 mpWindowImpl
->mpFrame
->ToTop( nSysFlags
);
267 if ( mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
.get() != this )
269 // remove window from the list
270 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
271 if ( mpWindowImpl
->mpNext
)
272 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
275 // coverity[copy_paste_error : FALSE] - this is correct mpLastOverlap, not mpPrev
276 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
279 // take AlwaysOnTop into account
280 bool bOnTop
= IsAlwaysOnTopEnabled();
281 vcl::Window
* pNextWin
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
286 if ( !pNextWin
->IsAlwaysOnTopEnabled() )
288 pNextWin
= pNextWin
->mpWindowImpl
->mpNext
;
292 // add the window to the list again
293 mpWindowImpl
->mpNext
= pNextWin
;
296 mpWindowImpl
->mpPrev
= pNextWin
->mpWindowImpl
->mpPrev
;
297 pNextWin
->mpWindowImpl
->mpPrev
= this;
301 mpWindowImpl
->mpPrev
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
;
302 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= this;
304 if ( mpWindowImpl
->mpPrev
)
305 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
307 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= this;
309 // recalculate ClipRegion of this and all overlapping windows
310 if ( IsReallyVisible() )
312 mpWindowImpl
->mpOverlapWindow
->ImplSetClipFlagOverlapWindows();
318 void Window::ImplStartToTop( ToTopFlags nFlags
)
320 ImplCalcToTopData aStartData
;
321 ImplCalcToTopData
* pCurData
;
322 vcl::Window
* pOverlapWindow
;
323 if ( ImplIsOverlapWindow() )
324 pOverlapWindow
= this;
326 pOverlapWindow
= mpWindowImpl
->mpOverlapWindow
;
328 // first calculate paint areas
329 vcl::Window
* pTempOverlapWindow
= pOverlapWindow
;
330 aStartData
.mpNext
= nullptr;
331 pCurData
= &aStartData
;
334 pTempOverlapWindow
->ImplCalcToTop( pCurData
);
335 if ( pCurData
->mpNext
)
336 pCurData
= pCurData
->mpNext
.get();
337 pTempOverlapWindow
= pTempOverlapWindow
->mpWindowImpl
->mpOverlapWindow
;
339 while ( !pTempOverlapWindow
->mpWindowImpl
->mbFrame
);
340 // next calculate the paint areas of the ChildOverlap windows
341 pTempOverlapWindow
= mpWindowImpl
->mpFirstOverlap
;
342 while ( pTempOverlapWindow
)
344 pTempOverlapWindow
->ImplCalcToTop( pCurData
);
345 if ( pCurData
->mpNext
)
346 pCurData
= pCurData
->mpNext
.get();
347 pTempOverlapWindow
= pTempOverlapWindow
->mpWindowImpl
->mpNext
;
350 // and next change the windows list
351 pTempOverlapWindow
= pOverlapWindow
;
354 pTempOverlapWindow
->ImplToTop( nFlags
);
355 pTempOverlapWindow
= pTempOverlapWindow
->mpWindowImpl
->mpOverlapWindow
;
357 while ( !pTempOverlapWindow
->mpWindowImpl
->mbFrame
);
358 // as last step invalidate the invalid areas
359 pCurData
= aStartData
.mpNext
.get();
362 pCurData
->mpWindow
->ImplInvalidateFrameRegion( pCurData
->mpInvalidateRegion
.get(), InvalidateFlags::Children
);
363 pCurData
= pCurData
->mpNext
.get();
367 void Window::ImplFocusToTop( ToTopFlags nFlags
, bool bReallyVisible
)
369 // do we need to fetch the focus?
370 if ( !(nFlags
& ToTopFlags::NoGrabFocus
) )
372 // first window with GrabFocus-Activate gets the focus
373 vcl::Window
* pFocusWindow
= this;
374 while ( !pFocusWindow
->ImplIsOverlapWindow() )
376 // if the window has no BorderWindow, we
377 // should always find the belonging BorderWindow
378 if ( !pFocusWindow
->mpWindowImpl
->mpBorderWindow
)
380 if ( pFocusWindow
->mpWindowImpl
->mnActivateMode
& ActivateModeFlags::GrabFocus
)
383 pFocusWindow
= pFocusWindow
->ImplGetParent();
385 if ( (pFocusWindow
->mpWindowImpl
->mnActivateMode
& ActivateModeFlags::GrabFocus
) &&
386 !pFocusWindow
->HasChildPathFocus( true ) )
387 pFocusWindow
->GrabFocus();
390 if ( bReallyVisible
)
391 ImplGenerateMouseMove();
394 void Window::ImplShowAllOverlaps()
396 vcl::Window
* pOverlapWindow
= mpWindowImpl
->mpFirstOverlap
;
397 while ( pOverlapWindow
)
399 if ( pOverlapWindow
->mpWindowImpl
->mbOverlapVisible
)
401 pOverlapWindow
->Show( true, ShowFlags::NoActivate
);
402 pOverlapWindow
->mpWindowImpl
->mbOverlapVisible
= false;
405 pOverlapWindow
= pOverlapWindow
->mpWindowImpl
->mpNext
;
409 void Window::ImplHideAllOverlaps()
411 vcl::Window
* pOverlapWindow
= mpWindowImpl
->mpFirstOverlap
;
412 while ( pOverlapWindow
)
414 if ( pOverlapWindow
->IsVisible() )
416 pOverlapWindow
->mpWindowImpl
->mbOverlapVisible
= true;
417 pOverlapWindow
->Show( false );
420 pOverlapWindow
= pOverlapWindow
->mpWindowImpl
->mpNext
;
424 void Window::ToTop( ToTopFlags nFlags
)
429 ImplStartToTop( nFlags
);
430 ImplFocusToTop( nFlags
, IsReallyVisible() );
433 void Window::SetZOrder( vcl::Window
* pRefWindow
, ZOrderFlags nFlags
)
436 if ( mpWindowImpl
->mpBorderWindow
)
438 mpWindowImpl
->mpBorderWindow
->SetZOrder( pRefWindow
, nFlags
);
442 if ( nFlags
& ZOrderFlags::First
)
444 if ( ImplIsOverlapWindow() )
445 pRefWindow
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
447 pRefWindow
= mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
;
448 nFlags
|= ZOrderFlags::Before
;
450 else if ( nFlags
& ZOrderFlags::Last
)
452 if ( ImplIsOverlapWindow() )
453 pRefWindow
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
;
455 pRefWindow
= mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
;
456 nFlags
|= ZOrderFlags::Behind
;
459 while ( pRefWindow
&& pRefWindow
->mpWindowImpl
->mpBorderWindow
)
460 pRefWindow
= pRefWindow
->mpWindowImpl
->mpBorderWindow
;
461 if (!pRefWindow
|| pRefWindow
== this || mpWindowImpl
->mbFrame
)
464 SAL_WARN_IF( pRefWindow
->mpWindowImpl
->mpParent
!= mpWindowImpl
->mpParent
, "vcl", "Window::SetZOrder() - pRefWindow has other parent" );
465 if ( nFlags
& ZOrderFlags::Before
)
467 if ( pRefWindow
->mpWindowImpl
->mpPrev
.get() == this )
470 if ( ImplIsOverlapWindow() )
472 if ( mpWindowImpl
->mpPrev
)
473 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
475 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= mpWindowImpl
->mpNext
;
476 if ( mpWindowImpl
->mpNext
)
477 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
479 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
480 if ( !pRefWindow
->mpWindowImpl
->mpPrev
)
481 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= this;
485 if ( mpWindowImpl
->mpPrev
)
486 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
488 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= mpWindowImpl
->mpNext
;
489 if ( mpWindowImpl
->mpNext
)
490 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
492 mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
= mpWindowImpl
->mpPrev
;
493 if ( !pRefWindow
->mpWindowImpl
->mpPrev
)
494 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= this;
497 mpWindowImpl
->mpPrev
= pRefWindow
->mpWindowImpl
->mpPrev
;
498 mpWindowImpl
->mpNext
= pRefWindow
;
499 if ( mpWindowImpl
->mpPrev
)
500 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
501 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= this;
503 else if ( nFlags
& ZOrderFlags::Behind
)
505 if ( pRefWindow
->mpWindowImpl
->mpNext
.get() == this )
508 if ( ImplIsOverlapWindow() )
510 if ( mpWindowImpl
->mpPrev
)
511 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
513 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
= mpWindowImpl
->mpNext
;
514 if ( mpWindowImpl
->mpNext
)
515 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
517 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= mpWindowImpl
->mpPrev
;
518 if ( !pRefWindow
->mpWindowImpl
->mpNext
)
519 mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpLastOverlap
= this;
523 if ( mpWindowImpl
->mpPrev
)
524 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= mpWindowImpl
->mpNext
;
526 mpWindowImpl
->mpParent
->mpWindowImpl
->mpFirstChild
= mpWindowImpl
->mpNext
;
527 if ( mpWindowImpl
->mpNext
)
528 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= mpWindowImpl
->mpPrev
;
530 mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
= mpWindowImpl
->mpPrev
;
531 if ( !pRefWindow
->mpWindowImpl
->mpNext
)
532 mpWindowImpl
->mpParent
->mpWindowImpl
->mpLastChild
= this;
535 mpWindowImpl
->mpPrev
= pRefWindow
;
536 mpWindowImpl
->mpNext
= pRefWindow
->mpWindowImpl
->mpNext
;
537 if ( mpWindowImpl
->mpNext
)
538 mpWindowImpl
->mpNext
->mpWindowImpl
->mpPrev
= this;
539 mpWindowImpl
->mpPrev
->mpWindowImpl
->mpNext
= this;
542 if ( !IsReallyVisible() )
545 if ( !mpWindowImpl
->mbInitWinClipRegion
&& mpWindowImpl
->maWinClipRegion
.IsEmpty() )
548 bool bInitWinClipRegion
= mpWindowImpl
->mbInitWinClipRegion
;
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
)
561 // Invalidate all windows which are next to each other
563 tools::Rectangle aWinRect
= GetOutputRectPixel();
564 vcl::Window
* pWindow
= nullptr;
565 if ( ImplIsOverlapWindow() )
567 if ( mpWindowImpl
->mpOverlapWindow
)
568 pWindow
= mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
571 pWindow
= ImplGetParent()->mpWindowImpl
->mpFirstChild
;
572 // Invalidate all windows in front of us and which are covered by us
575 if ( pWindow
== this )
577 tools::Rectangle aCompRect
= pWindow
->GetOutputRectPixel();
578 if ( aWinRect
.Overlaps( aCompRect
) )
579 pWindow
->Invalidate( InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
580 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
583 // If we are covered by a window in the background
584 // we should redraw it
587 if ( pWindow
!= this )
589 tools::Rectangle aCompRect
= pWindow
->GetOutputRectPixel();
590 if ( aWinRect
.Overlaps( aCompRect
) )
592 Invalidate( InvalidateFlags::Children
| InvalidateFlags::NoTransparent
);
596 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
600 void Window::EnableAlwaysOnTop( bool bEnable
)
603 mpWindowImpl
->mbAlwaysOnTop
= bEnable
;
605 if ( mpWindowImpl
->mpBorderWindow
)
606 mpWindowImpl
->mpBorderWindow
->EnableAlwaysOnTop( bEnable
);
607 else if ( bEnable
&& IsReallyVisible() )
610 if ( mpWindowImpl
->mbFrame
)
611 mpWindowImpl
->mpFrame
->SetAlwaysOnTop( bEnable
);
614 bool Window::IsTopWindow() const
616 if ( !mpWindowImpl
|| mpWindowImpl
->mbInDispose
)
619 // topwindows must be frames or they must have a borderwindow which is a frame
620 if( !mpWindowImpl
->mbFrame
&& (!mpWindowImpl
->mpBorderWindow
|| !mpWindowImpl
->mpBorderWindow
->mpWindowImpl
->mbFrame
) )
624 if( mpWindowImpl
->mpWinData
->mnIsTopWindow
== sal_uInt16(~0)) // still uninitialized
626 // #113722#, cache result of expensive queryInterface call
627 vcl::Window
*pThisWin
= const_cast<vcl::Window
*>(this);
628 uno::Reference
< XTopWindow
> xTopWindow( pThisWin
->GetComponentInterface(), UNO_QUERY
);
629 pThisWin
->mpWindowImpl
->mpWinData
->mnIsTopWindow
= xTopWindow
.is() ? 1 : 0;
631 return mpWindowImpl
->mpWinData
->mnIsTopWindow
== 1;
634 vcl::Window
* Window::ImplFindWindow( const Point
& rFramePos
)
636 vcl::Window
* pTempWindow
;
637 vcl::Window
* pFindWindow
;
639 // first check all overlapping windows
640 pTempWindow
= mpWindowImpl
->mpFirstOverlap
;
641 while ( pTempWindow
)
643 pFindWindow
= pTempWindow
->ImplFindWindow( rFramePos
);
646 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
649 // then we check our window
650 if ( !mpWindowImpl
->mbVisible
)
653 WindowHitTest nHitTest
= ImplHitTest( rFramePos
);
654 if ( nHitTest
& WindowHitTest::Inside
)
656 // and then we check all child windows
657 pTempWindow
= mpWindowImpl
->mpFirstChild
;
658 while ( pTempWindow
)
660 pFindWindow
= pTempWindow
->ImplFindWindow( rFramePos
);
663 pTempWindow
= pTempWindow
->mpWindowImpl
->mpNext
;
666 if ( nHitTest
& WindowHitTest::Transparent
)
675 bool Window::ImplIsRealParentPath( const vcl::Window
* pWindow
) const
677 pWindow
= pWindow
->GetParent();
680 if ( pWindow
== this )
682 pWindow
= pWindow
->GetParent();
688 bool Window::ImplIsChild( const vcl::Window
* pWindow
, bool bSystemWindow
) const
692 if ( !bSystemWindow
&& pWindow
->ImplIsOverlapWindow() )
695 pWindow
= pWindow
->ImplGetParent();
697 if ( pWindow
== this )
705 bool Window::ImplIsWindowOrChild( const vcl::Window
* pWindow
, bool bSystemWindow
) const
707 if ( this == pWindow
)
709 return ImplIsChild( pWindow
, bSystemWindow
);
712 void Window::ImplResetReallyVisible()
714 bool bBecameReallyInvisible
= mpWindowImpl
->mbReallyVisible
;
716 GetOutDev()->mbDevOutput
= false;
717 mpWindowImpl
->mbReallyVisible
= false;
718 mpWindowImpl
->mbReallyShown
= false;
720 // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge.
721 // For this, the data member of the event must not be NULL.
722 // Previously, we did this in Window::Show, but there some events got lost in certain situations.
723 if( bBecameReallyInvisible
&& ImplIsAccessibleCandidate() )
724 CallEventListeners( VclEventId::WindowHide
, this );
725 // TODO. It's kind of a hack that we're re-using the VclEventId::WindowHide. Normally, we should
726 // introduce another event which explicitly triggers the Accessibility implementations.
728 vcl::Window
* pWindow
= mpWindowImpl
->mpFirstOverlap
;
731 if ( pWindow
->mpWindowImpl
->mbReallyVisible
)
732 pWindow
->ImplResetReallyVisible();
733 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
736 pWindow
= mpWindowImpl
->mpFirstChild
;
739 if ( pWindow
->mpWindowImpl
->mbReallyVisible
)
740 pWindow
->ImplResetReallyVisible();
741 pWindow
= pWindow
->mpWindowImpl
->mpNext
;
745 void Window::ImplUpdateWindowPtr( vcl::Window
* pWindow
)
747 if ( mpWindowImpl
->mpFrameWindow
!= pWindow
->mpWindowImpl
->mpFrameWindow
)
750 OutputDevice
*pOutDev
= GetOutDev();
751 pOutDev
->ReleaseGraphics();
754 mpWindowImpl
->mpFrameData
= pWindow
->mpWindowImpl
->mpFrameData
;
755 if (mpWindowImpl
->mpFrame
!= pWindow
->mpWindowImpl
->mpFrame
)
757 mpWindowImpl
->mpFrame
= pWindow
->mpWindowImpl
->mpFrame
;
758 if (mpWindowImpl
->mpSysObj
)
759 mpWindowImpl
->mpSysObj
->Reparent(mpWindowImpl
->mpFrame
);
761 mpWindowImpl
->mpFrameWindow
= pWindow
->mpWindowImpl
->mpFrameWindow
;
762 if ( pWindow
->ImplIsOverlapWindow() )
763 mpWindowImpl
->mpOverlapWindow
= pWindow
;
765 mpWindowImpl
->mpOverlapWindow
= pWindow
->mpWindowImpl
->mpOverlapWindow
;
767 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
770 pChild
->ImplUpdateWindowPtr( pWindow
);
771 pChild
= pChild
->mpWindowImpl
->mpNext
;
775 void Window::ImplUpdateWindowPtr()
777 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
780 pChild
->ImplUpdateWindowPtr( this );
781 pChild
= pChild
->mpWindowImpl
->mpNext
;
785 void Window::ImplUpdateOverlapWindowPtr( bool bNewFrame
)
787 bool bVisible
= IsVisible();
789 ImplRemoveWindow( bNewFrame
);
790 vcl::Window
* pRealParent
= mpWindowImpl
->mpRealParent
;
791 ImplInsertWindow( ImplGetParent() );
792 mpWindowImpl
->mpRealParent
= pRealParent
;
793 ImplUpdateWindowPtr();
794 if ( ImplUpdatePos() )
795 ImplUpdateSysObjPos();
799 vcl::Window
* pOverlapWindow
= mpWindowImpl
->mpFirstOverlap
;
800 while ( pOverlapWindow
)
802 vcl::Window
* pNextOverlapWindow
= pOverlapWindow
->mpWindowImpl
->mpNext
;
803 pOverlapWindow
->ImplUpdateOverlapWindowPtr( bNewFrame
);
804 pOverlapWindow
= pNextOverlapWindow
;
812 SystemWindow
* Window::GetSystemWindow() const
815 const vcl::Window
* pWin
= this;
816 while ( pWin
&& !pWin
->IsSystemWindow() )
817 pWin
= pWin
->GetParent();
818 return static_cast<SystemWindow
*>(const_cast<Window
*>(pWin
));
821 static SystemWindow
*ImplGetLastSystemWindow( vcl::Window
*pWin
)
823 // get the most top-level system window, the one that contains the taskpanelist
824 SystemWindow
*pSysWin
= nullptr;
827 vcl::Window
*pMyParent
= pWin
;
830 if ( pMyParent
->IsSystemWindow() )
831 pSysWin
= static_cast<SystemWindow
*>(pMyParent
);
832 pMyParent
= pMyParent
->GetParent();
837 void Window::SetParent( vcl::Window
* pNewParent
)
839 SAL_WARN_IF( !pNewParent
, "vcl", "Window::SetParent(): pParent == NULL" );
840 SAL_WARN_IF( pNewParent
== this, "vcl", "someone tried to reparent a window to itself" );
842 if( !pNewParent
|| pNewParent
== this )
845 // check if the taskpanelist would change and move the window pointer accordingly
846 SystemWindow
*pSysWin
= ImplGetLastSystemWindow(this);
847 SystemWindow
*pNewSysWin
= nullptr;
848 bool bChangeTaskPaneList
= false;
849 if( pSysWin
&& pSysWin
->ImplIsInTaskPaneList( this ) )
851 pNewSysWin
= ImplGetLastSystemWindow( pNewParent
);
852 if( pNewSysWin
&& pNewSysWin
!= pSysWin
)
854 bChangeTaskPaneList
= true;
855 pSysWin
->GetTaskPaneList()->RemoveWindow( this );
858 // remove ownerdraw decorated windows from list in the top-most frame window
859 if( (GetStyle() & WB_OWNERDRAWDECORATION
) && mpWindowImpl
->mbFrame
)
861 ::std::vector
< VclPtr
<vcl::Window
> >& rList
= ImplGetOwnerDrawList();
862 auto p
= ::std::find( rList
.begin(), rList
.end(), VclPtr
<vcl::Window
>(this) );
863 if( p
!= rList
.end() )
867 ImplSetFrameParent( pNewParent
);
869 if ( mpWindowImpl
->mpBorderWindow
)
871 mpWindowImpl
->mpRealParent
= pNewParent
;
872 mpWindowImpl
->mpBorderWindow
->SetParent( pNewParent
);
876 if ( mpWindowImpl
->mpParent
.get() == pNewParent
)
879 if ( mpWindowImpl
->mbFrame
)
880 mpWindowImpl
->mpFrame
->SetParent( pNewParent
->mpWindowImpl
->mpFrame
);
882 bool bVisible
= IsVisible();
883 Show( false, ShowFlags::NoFocusChange
);
885 // check if the overlap window changes
886 vcl::Window
* pOldOverlapWindow
;
887 vcl::Window
* pNewOverlapWindow
= nullptr;
888 if ( ImplIsOverlapWindow() )
889 pOldOverlapWindow
= nullptr;
892 pNewOverlapWindow
= pNewParent
->ImplGetFirstOverlapWindow();
893 if ( mpWindowImpl
->mpOverlapWindow
.get() != pNewOverlapWindow
)
894 pOldOverlapWindow
= mpWindowImpl
->mpOverlapWindow
;
896 pOldOverlapWindow
= nullptr;
899 // convert windows in the hierarchy
900 bool bFocusOverlapWin
= HasChildPathFocus( true );
901 bool bFocusWin
= HasChildPathFocus();
902 bool bNewFrame
= pNewParent
->mpWindowImpl
->mpFrameWindow
!= mpWindowImpl
->mpFrameWindow
;
905 if ( mpWindowImpl
->mpFrameData
->mpFocusWin
)
907 if ( IsWindowOrChild( mpWindowImpl
->mpFrameData
->mpFocusWin
) )
908 mpWindowImpl
->mpFrameData
->mpFocusWin
= nullptr;
910 if ( mpWindowImpl
->mpFrameData
->mpMouseMoveWin
)
912 if ( IsWindowOrChild( mpWindowImpl
->mpFrameData
->mpMouseMoveWin
) )
913 mpWindowImpl
->mpFrameData
->mpMouseMoveWin
= nullptr;
915 if ( mpWindowImpl
->mpFrameData
->mpMouseDownWin
)
917 if ( IsWindowOrChild( mpWindowImpl
->mpFrameData
->mpMouseDownWin
) )
918 mpWindowImpl
->mpFrameData
->mpMouseDownWin
= nullptr;
921 ImplRemoveWindow( bNewFrame
);
922 ImplInsertWindow( pNewParent
);
923 if ( mpWindowImpl
->mnParentClipMode
& ParentClipMode::Clip
)
924 pNewParent
->mpWindowImpl
->mbClipChildren
= true;
925 ImplUpdateWindowPtr();
926 if ( ImplUpdatePos() )
927 ImplUpdateSysObjPos();
929 // If the Overlap-Window has changed, we need to test whether
930 // OverlapWindows that had the Child window as their parent
931 // need to be put into the window hierarchy.
932 if ( ImplIsOverlapWindow() )
936 vcl::Window
* pOverlapWindow
= mpWindowImpl
->mpFirstOverlap
;
937 while ( pOverlapWindow
)
939 vcl::Window
* pNextOverlapWindow
= pOverlapWindow
->mpWindowImpl
->mpNext
;
940 pOverlapWindow
->ImplUpdateOverlapWindowPtr( bNewFrame
);
941 pOverlapWindow
= pNextOverlapWindow
;
945 else if ( pOldOverlapWindow
)
949 (pOldOverlapWindow
->mpWindowImpl
->mpLastFocusWindow
&&
950 IsWindowOrChild( pOldOverlapWindow
->mpWindowImpl
->mpLastFocusWindow
)) )
951 pOldOverlapWindow
->mpWindowImpl
->mpLastFocusWindow
= nullptr;
953 vcl::Window
* pOverlapWindow
= pOldOverlapWindow
->mpWindowImpl
->mpFirstOverlap
;
954 while ( pOverlapWindow
)
956 vcl::Window
* pNextOverlapWindow
= pOverlapWindow
->mpWindowImpl
->mpNext
;
957 if ( ImplIsRealParentPath( pOverlapWindow
->ImplGetWindow() ) )
958 pOverlapWindow
->ImplUpdateOverlapWindowPtr( bNewFrame
);
959 pOverlapWindow
= pNextOverlapWindow
;
962 // update activate-status at next overlap window
963 if ( HasChildPathFocus( true ) )
964 ImplCallFocusChangeActivate( pNewOverlapWindow
, pOldOverlapWindow
);
967 // also convert Activate-Status
970 if ( (GetType() == WindowType::BORDERWINDOW
) &&
971 (ImplGetWindow()->GetType() == WindowType::FLOATINGWINDOW
) )
972 static_cast<ImplBorderWindow
*>(this)->SetDisplayActive( mpWindowImpl
->mpFrameData
->mbHasFocus
);
975 // when required give focus to new frame if
976 // FocusWindow is changed with SetParent()
977 if ( bFocusOverlapWin
)
979 mpWindowImpl
->mpFrameData
->mpFocusWin
= Application::GetFocusWindow();
980 if ( !mpWindowImpl
->mpFrameData
->mbHasFocus
)
982 mpWindowImpl
->mpFrame
->ToTop( SalFrameToTop::NONE
);
986 // Assure DragSource and DropTarget members are created
992 if( bChangeTaskPaneList
)
993 pNewSysWin
->GetTaskPaneList()->AddWindow( this );
995 if( (GetStyle() & WB_OWNERDRAWDECORATION
) && mpWindowImpl
->mbFrame
)
996 ImplGetOwnerDrawList().emplace_back(this );
999 Show( true, ShowFlags::NoFocusChange
| ShowFlags::NoActivate
);
1002 bool Window::IsAncestorOf( const vcl::Window
& rWindow
) const
1004 return ImplIsRealParentPath(&rWindow
);
1007 sal_uInt16
Window::GetChildCount() const
1012 sal_uInt16 nChildCount
= 0;
1013 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
1017 pChild
= pChild
->mpWindowImpl
->mpNext
;
1023 vcl::Window
* Window::GetChild( sal_uInt16 nChild
) const
1028 sal_uInt16 nChildCount
= 0;
1029 vcl::Window
* pChild
= mpWindowImpl
->mpFirstChild
;
1032 if ( nChild
== nChildCount
)
1034 pChild
= pChild
->mpWindowImpl
->mpNext
;
1041 vcl::Window
* Window::GetWindow( GetWindowType nType
) const
1048 case GetWindowType::Parent
:
1049 return mpWindowImpl
->mpRealParent
;
1051 case GetWindowType::FirstChild
:
1052 return mpWindowImpl
->mpFirstChild
;
1054 case GetWindowType::LastChild
:
1055 return mpWindowImpl
->mpLastChild
;
1057 case GetWindowType::Prev
:
1058 return mpWindowImpl
->mpPrev
;
1060 case GetWindowType::Next
:
1061 return mpWindowImpl
->mpNext
;
1063 case GetWindowType::FirstOverlap
:
1064 return mpWindowImpl
->mpFirstOverlap
;
1066 case GetWindowType::Overlap
:
1067 if ( ImplIsOverlapWindow() )
1068 return const_cast<vcl::Window
*>(this);
1070 return mpWindowImpl
->mpOverlapWindow
;
1072 case GetWindowType::ParentOverlap
:
1073 if ( ImplIsOverlapWindow() )
1074 return mpWindowImpl
->mpOverlapWindow
;
1076 return mpWindowImpl
->mpOverlapWindow
->mpWindowImpl
->mpOverlapWindow
;
1078 case GetWindowType::Client
:
1079 return this->ImplGetWindow();
1081 case GetWindowType::RealParent
:
1082 return ImplGetParent();
1084 case GetWindowType::Frame
:
1085 return mpWindowImpl
->mpFrameWindow
;
1087 case GetWindowType::Border
:
1088 if ( mpWindowImpl
->mpBorderWindow
)
1089 return mpWindowImpl
->mpBorderWindow
->GetWindow( GetWindowType::Border
);
1090 return const_cast<vcl::Window
*>(this);
1092 case GetWindowType::FirstTopWindowChild
:
1093 return ImplGetWinData()->maTopWindowChildren
.empty() ? nullptr : (*ImplGetWinData()->maTopWindowChildren
.begin()).get();
1095 case GetWindowType::NextTopWindowSibling
:
1097 if ( !mpWindowImpl
->mpRealParent
)
1099 const ::std::list
< VclPtr
<vcl::Window
> >& rTopWindows( mpWindowImpl
->mpRealParent
->ImplGetWinData()->maTopWindowChildren
);
1100 ::std::list
< VclPtr
<vcl::Window
> >::const_iterator myPos
=
1101 ::std::find( rTopWindows
.begin(), rTopWindows
.end(), this );
1102 if ( ( myPos
== rTopWindows
.end() ) || ( ++myPos
== rTopWindows
.end() ) )
1112 bool Window::IsChild( const vcl::Window
* pWindow
) const
1116 if ( pWindow
->ImplIsOverlapWindow() )
1119 pWindow
= pWindow
->ImplGetParent();
1121 if ( pWindow
== this )
1129 bool Window::IsWindowOrChild( const vcl::Window
* pWindow
, bool bSystemWindow
) const
1132 if ( this == pWindow
)
1134 return ImplIsChild( pWindow
, bSystemWindow
);
1137 void Window::ImplSetFrameParent( const vcl::Window
* pParent
)
1139 vcl::Window
* pFrameWindow
= ImplGetSVData()->maFrameData
.mpFirstFrame
;
1140 while( pFrameWindow
)
1142 // search all frames that are children of this window
1143 // and reparent them
1144 if( ImplIsRealParentPath( pFrameWindow
) )
1146 SAL_WARN_IF( mpWindowImpl
->mpFrame
== pFrameWindow
->mpWindowImpl
->mpFrame
, "vcl", "SetFrameParent to own" );
1147 SAL_WARN_IF( !mpWindowImpl
->mpFrame
, "vcl", "no frame" );
1148 SalFrame
* pParentFrame
= pParent
? pParent
->mpWindowImpl
->mpFrame
: nullptr;
1149 pFrameWindow
->mpWindowImpl
->mpFrame
->SetParent( pParentFrame
);
1151 pFrameWindow
= pFrameWindow
->mpWindowImpl
->mpFrameData
->mpNextFrame
;
1155 } /* namespace vcl */
1157 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */