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