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