bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / window / dockmgr.cxx
blob87ca621f7f28789c00665959dd9ccd830434f947
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/time.hxx>
21 #include <sal/log.hxx>
22 #include <o3tl/deleter.hxx>
24 #include <brdwin.hxx>
25 #include <svdata.hxx>
26 #include <window.h>
28 #include <vcl/event.hxx>
29 #include <vcl/toolkit/floatwin.hxx>
30 #include <vcl/dockwin.hxx>
31 #include <vcl/toolbox.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/timer.hxx>
34 #include <vcl/settings.hxx>
36 #include "impldockingwrapper.hxx"
38 #define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE)
40 namespace {
42 class ImplDockFloatWin2 : public FloatingWindow
44 private:
45 ImplDockingWindowWrapper* mpDockWin;
46 sal_uInt64 mnLastTicks;
47 Timer m_aDockTimer;
48 Timer m_aEndDockTimer;
49 Point maDockPos;
50 tools::Rectangle maDockRect;
51 bool mbInMove;
52 ImplSVEvent * mnLastUserEvent;
54 DECL_LINK(DockingHdl, void *, void);
55 DECL_LINK(DockTimerHdl, Timer *, void);
56 DECL_LINK(EndDockTimerHdl, Timer *, void);
57 public:
58 ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits,
59 ImplDockingWindowWrapper* pDockingWin );
60 virtual ~ImplDockFloatWin2() override;
61 virtual void dispose() override;
63 virtual void Move() override;
64 virtual void Resize() override;
65 virtual void TitleButtonClick( TitleButton nButton ) override;
66 virtual void Resizing( Size& rSize ) override;
67 virtual bool Close() override;
72 ImplDockFloatWin2::ImplDockFloatWin2( vcl::Window* pParent, WinBits nWinBits,
73 ImplDockingWindowWrapper* pDockingWin ) :
74 FloatingWindow( pParent, nWinBits ),
75 mpDockWin( pDockingWin ),
76 mnLastTicks( tools::Time::GetSystemTicks() ),
77 m_aDockTimer("vcl::ImplDockFloatWin2 m_aDockTimer"),
78 m_aEndDockTimer( "vcl::ImplDockFloatWin2 m_aEndDockTimer" ),
79 mbInMove( false ),
80 mnLastUserEvent( nullptr )
82 // copy state of DockingWindow
83 if ( pDockingWin )
85 GetOutDev()->SetSettings( pDockingWin->GetWindow()->GetSettings() );
86 Enable( pDockingWin->GetWindow()->IsEnabled(), false );
87 EnableInput( pDockingWin->GetWindow()->IsInputEnabled(), false );
88 AlwaysEnableInput( pDockingWin->GetWindow()->IsAlwaysEnableInput(), false );
89 EnableAlwaysOnTop( pDockingWin->GetWindow()->IsAlwaysOnTopEnabled() );
90 SetActivateMode( pDockingWin->GetWindow()->GetActivateMode() );
93 SetBackground( GetSettings().GetStyleSettings().GetFaceColor() );
95 m_aDockTimer.SetInvokeHandler( LINK( this, ImplDockFloatWin2, DockTimerHdl ) );
96 m_aDockTimer.SetPriority( TaskPriority::HIGH_IDLE );
97 m_aDockTimer.SetTimeout( 50 );
99 m_aEndDockTimer.SetInvokeHandler( LINK( this, ImplDockFloatWin2, EndDockTimerHdl ) );
100 m_aEndDockTimer.SetPriority( TaskPriority::HIGH_IDLE );
101 m_aEndDockTimer.SetTimeout( 50 );
104 ImplDockFloatWin2::~ImplDockFloatWin2()
106 disposeOnce();
109 void ImplDockFloatWin2::dispose()
111 if( mnLastUserEvent )
112 Application::RemoveUserEvent( mnLastUserEvent );
113 FloatingWindow::dispose();
116 IMPL_LINK_NOARG(ImplDockFloatWin2, DockTimerHdl, Timer *, void)
118 SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "docktimer called but not floating" );
120 PointerState aState = GetPointerState();
122 if( aState.mnState & KEY_MOD1 )
124 // i43499 CTRL disables docking now
125 mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
126 if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) )
127 m_aDockTimer.Start();
129 else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
131 mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
132 mpDockWin->EndDocking( maDockRect, false );
134 else
136 mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow );
137 m_aDockTimer.Start();
141 IMPL_LINK_NOARG(ImplDockFloatWin2, EndDockTimerHdl, Timer *, void)
143 SAL_WARN_IF( !mpDockWin->IsFloatingMode(), "vcl", "enddocktimer called but not floating" );
145 PointerState aState = GetPointerState();
146 if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) )
148 mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
149 mpDockWin->EndDocking( maDockRect, true );
151 else
152 m_aEndDockTimer.Start();
155 IMPL_LINK_NOARG(ImplDockFloatWin2, DockingHdl, void*, void)
157 // called during move of a floating window
158 mnLastUserEvent = nullptr;
160 vcl::Window *pDockingArea = mpDockWin->GetWindow()->GetParent();
161 PointerState aState = pDockingArea->GetPointerState();
163 bool bRealMove = true;
164 if( GetStyle() & WB_OWNERDRAWDECORATION )
166 // for windows with ownerdraw decoration
167 // we allow docking only when the window was moved
168 // by dragging its caption
169 // and ignore move request due to resizing
170 vcl::Window *pBorder = GetWindow( GetWindowType::Border );
171 if( pBorder != this )
173 tools::Rectangle aBorderRect( Point(), pBorder->GetSizePixel() );
174 sal_Int32 nLeft, nTop, nRight, nBottom;
175 GetBorder( nLeft, nTop, nRight, nBottom );
176 // limit borderrect to the caption part only and without the resizing borders
177 aBorderRect.SetBottom( aBorderRect.Top() + nTop );
178 aBorderRect.AdjustLeft(nLeft );
179 aBorderRect.AdjustRight( -nRight );
181 PointerState aBorderState = pBorder->GetPointerState();
182 bRealMove = aBorderRect.Contains( aBorderState.maPos );
186 if( mpDockWin->GetWindow()->IsVisible() &&
187 (tools::Time::GetSystemTicks() - mnLastTicks > 500) &&
188 ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) &&
189 !(aState.mnState & KEY_MOD1) && // i43499 CTRL disables docking now
190 bRealMove )
192 maDockPos = pDockingArea->OutputToScreenPixel( pDockingArea->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) );
193 maDockRect = tools::Rectangle( maDockPos, mpDockWin->GetSizePixel() );
195 // mouse pos in screen pixels
196 Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos );
198 if( ! mpDockWin->IsDocking() )
199 mpDockWin->StartDocking( aMousePos, maDockRect );
201 bool bFloatMode = mpDockWin->Docking( aMousePos, maDockRect );
203 if( ! bFloatMode )
205 // indicates that the window could be docked at maDockRect
206 maDockRect.SetPos( mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ScreenToOutputPixel(
207 maDockRect.TopLeft() ) );
208 mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, ShowTrackFlags::Big | ShowTrackFlags::TrackWindow );
209 m_aEndDockTimer.Stop();
210 m_aDockTimer.Invoke();
212 else
214 mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking();
215 m_aDockTimer.Stop();
216 m_aEndDockTimer.Invoke();
219 mbInMove = false;
222 void ImplDockFloatWin2::Move()
224 if( mbInMove )
225 return;
227 mbInMove = true;
228 FloatingWindow::Move();
229 mpDockWin->GetWindow()->Move();
232 * note: the window should only dock if KEY_MOD1 is pressed
233 * and the user releases all mouse buttons. The real problem here
234 * is that we don't get mouse events (at least not on X)
235 * if the mouse is on the decoration. So we have to start an
236 * awkward timer based process that polls the modifier/buttons
237 * to see whether they are in the right condition shortly after the
238 * last Move message.
240 if( ! mnLastUserEvent )
241 mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin2, DockingHdl ), nullptr, true );
244 void ImplDockFloatWin2::Resize()
246 // forwarding of resize only required if we have no borderwindow ( GetWindow() then returns 'this' )
247 if( GetWindow( GetWindowType::Border ) == this )
249 FloatingWindow::Resize();
250 Size aSize( GetSizePixel() );
251 mpDockWin->GetWindow()->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), PosSizeFlags::PosSize ); // TODO: is this needed ???
255 void ImplDockFloatWin2::TitleButtonClick( TitleButton nButton )
257 FloatingWindow::TitleButtonClick( nButton );
258 mpDockWin->TitleButtonClick( nButton );
261 void ImplDockFloatWin2::Resizing( Size& rSize )
263 FloatingWindow::Resizing( rSize );
264 mpDockWin->Resizing( rSize );
267 bool ImplDockFloatWin2::Close()
269 return true;
272 DockingManager::DockingManager()
276 DockingManager::~DockingManager()
280 ImplDockingWindowWrapper* DockingManager::GetDockingWindowWrapper( const vcl::Window *pWindow )
282 for( const auto& xWrapper : mvDockingWindows )
284 if (xWrapper && xWrapper->mpDockingWindow == pWindow)
285 return xWrapper.get();
287 return nullptr;
290 bool DockingManager::IsDockable( const vcl::Window *pWindow )
292 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
295 if( pWindow->HasDockingHandler() )
296 return true;
298 return (pWrapper != nullptr);
301 bool DockingManager::IsFloating( const vcl::Window *pWindow )
303 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
304 if( pWrapper )
305 return pWrapper->IsFloatingMode();
306 else
307 return false;
310 bool DockingManager::IsLocked( const vcl::Window *pWindow )
312 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
313 return pWrapper && pWrapper->IsLocked();
316 void DockingManager::Lock( const vcl::Window *pWindow )
318 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
319 if( pWrapper )
320 pWrapper->Lock();
323 void DockingManager::Unlock( const vcl::Window *pWindow )
325 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
326 if( pWrapper )
327 pWrapper->Unlock();
330 void DockingManager::SetFloatingMode( const vcl::Window *pWindow, bool bFloating )
332 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
333 if( pWrapper )
334 pWrapper->SetFloatingMode( bFloating );
337 void DockingManager::StartPopupMode( const vcl::Window *pWindow, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags )
339 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
340 if( pWrapper )
341 pWrapper->StartPopupMode( rRect, nFlags );
344 void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWindow, FloatWinPopupFlags nFlags )
346 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
347 if( pWrapper )
348 pWrapper->StartPopupMode( pParentToolBox, nFlags );
351 void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWindow )
353 StartPopupMode( pParentToolBox, pWindow, FloatWinPopupFlags::AllowTearOff |
354 FloatWinPopupFlags::AllMouseButtonClose |
355 FloatWinPopupFlags::NoMouseUpClose );
358 bool DockingManager::IsInPopupMode( const vcl::Window *pWindow )
360 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
361 return pWrapper && pWrapper->IsInPopupMode();
364 void DockingManager::EndPopupMode( const vcl::Window *pWin )
366 ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin );
367 if( pWrapper && pWrapper->GetFloatingWindow() && static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->IsInPopupMode() )
368 static_cast<FloatingWindow*>(pWrapper->GetFloatingWindow())->EndPopupMode();
371 SystemWindow* DockingManager::GetFloatingWindow(const vcl::Window *pWin)
373 ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin );
374 if (pWrapper)
375 return pWrapper->GetFloatingWindow();
376 return nullptr;
379 void DockingManager::SetPopupModeEndHdl( const vcl::Window *pWindow, const Link<FloatingWindow*,void>& rLink )
381 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
382 if( pWrapper )
383 pWrapper->SetPopupModeEndHdl(rLink);
386 void DockingManager::AddWindow( const vcl::Window *pWindow )
388 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
389 if( pWrapper )
390 return;
391 mvDockingWindows.emplace_back( new ImplDockingWindowWrapper( pWindow ) );
394 void DockingManager::RemoveWindow( const vcl::Window *pWindow )
396 for( auto it = mvDockingWindows.begin(); it != mvDockingWindows.end(); ++it )
398 const auto& xWrapper = *it;
399 if (xWrapper && xWrapper->mpDockingWindow == pWindow)
401 // deleting wrappers calls set of actions which may want to use
402 // wrapper we want to delete - avoid crash using temporary owner
403 // while erasing
404 auto pTemporaryOwner = std::move(*it);
405 mvDockingWindows.erase( it );
406 break;
411 void DockingManager::SetPosSizePixel( vcl::Window const *pWindow, tools::Long nX, tools::Long nY,
412 tools::Long nWidth, tools::Long nHeight,
413 PosSizeFlags nFlags )
415 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
416 if( pWrapper )
417 pWrapper->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
420 tools::Rectangle DockingManager::GetPosSizePixel( const vcl::Window *pWindow )
422 tools::Rectangle aRect;
423 ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
424 if( pWrapper )
425 aRect = tools::Rectangle( pWrapper->GetPosPixel(), pWrapper->GetSizePixel() );
427 return aRect;
430 class ImplPopupFloatWin : public FloatingWindow
432 private:
433 bool mbToolBox;
435 public:
436 ImplPopupFloatWin( vcl::Window* pParent, bool bToolBox );
437 virtual ~ImplPopupFloatWin() override;
438 virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
441 ImplPopupFloatWin::ImplPopupFloatWin( vcl::Window* pParent, bool bToolBox ) :
442 FloatingWindow( pParent, bToolBox ? WB_BORDER | WB_POPUP | WB_SYSTEMWINDOW | WB_NOSHADOW : WB_STDPOPUP ),
443 mbToolBox( bToolBox )
445 if ( bToolBox )
447 // indicate window type, required for accessibility
448 // which should not see this window as a toplevel window
449 mpWindowImpl->mbToolbarFloatingWindow = true;
453 ImplPopupFloatWin::~ImplPopupFloatWin()
455 disposeOnce();
458 css::uno::Reference< css::accessibility::XAccessible > ImplPopupFloatWin::CreateAccessible()
460 if ( !mbToolBox )
461 return FloatingWindow::CreateAccessible();
463 // switch off direct accessibility support for this window
465 // this is to avoid appearance of this window as standalone window in the accessibility hierarchy
466 // as this window is only used as a helper for subtoolbars that are not teared-off, the parent toolbar
467 // has to provide accessibility support (as implemented in the toolkit)
468 // so the contained toolbar should appear as child of the corresponding toolbar item of the parent toolbar
469 return css::uno::Reference< css::accessibility::XAccessible >();
472 ImplDockingWindowWrapper::ImplDockingWindowWrapper( const vcl::Window *pWindow )
473 : mpDockingWindow(const_cast<vcl::Window*>(pWindow))
474 , mpFloatWin(nullptr)
475 , mpOldBorderWin(nullptr)
476 , mpParent(pWindow->GetParent())
477 , maMaxOutSize( SHRT_MAX, SHRT_MAX )
478 , mnTrackX(0)
479 , mnTrackY(0)
480 , mnTrackWidth(0)
481 , mnTrackHeight(0)
482 , mnDockLeft(0)
483 , mnDockTop(0)
484 , mnDockRight(0)
485 , mnDockBottom(0)
486 , mnFloatBits(WB_BORDER | WB_CLOSEABLE | WB_SIZEABLE | (pWindow->GetStyle() & DOCKWIN_FLOATSTYLES))
487 , mbDockCanceled(false)
488 , mbDocking(false)
489 , mbLastFloatMode(false)
490 , mbDockBtn(false)
491 , mbHideBtn(false)
492 // must be enabled in Window::Notify to prevent permanent docking during mouse move
493 , mbStartDockingEnabled(false)
494 , mbLocked(false)
496 assert(mpDockingWindow);
497 DockingWindow *pDockWin = dynamic_cast< DockingWindow* > ( mpDockingWindow.get() );
498 if( pDockWin )
499 mnFloatBits = pDockWin->GetFloatStyle();
502 ImplDockingWindowWrapper::~ImplDockingWindowWrapper()
504 if ( IsFloatingMode() )
506 GetWindow()->Show( false, ShowFlags::NoFocusChange );
507 SetFloatingMode(false);
511 void ImplDockingWindowWrapper::ImplStartDocking( const Point& rPos )
513 if( !mbStartDockingEnabled )
514 return;
516 maMouseOff = rPos;
517 mbDocking = true;
518 mbLastFloatMode = IsFloatingMode();
520 // calculate FloatingBorder
521 VclPtr<FloatingWindow> pWin;
522 if ( mpFloatWin )
523 pWin = mpFloatWin;
524 else
525 pWin = VclPtr<ImplDockFloatWin2>::Create( mpParent, mnFloatBits, nullptr );
526 pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom );
527 if ( !mpFloatWin )
528 pWin.disposeAndClear();
530 Point aPos = GetWindow()->ImplOutputToFrame( Point() );
531 Size aSize = GetWindow()->GetOutputSizePixel();
532 mnTrackX = aPos.X();
533 mnTrackY = aPos.Y();
534 mnTrackWidth = aSize.Width();
535 mnTrackHeight = aSize.Height();
537 if ( mbLastFloatMode )
539 maMouseOff.AdjustX(mnDockLeft );
540 maMouseOff.AdjustY(mnDockTop );
541 mnTrackX -= mnDockLeft;
542 mnTrackY -= mnDockTop;
543 mnTrackWidth += mnDockLeft+mnDockRight;
544 mnTrackHeight += mnDockTop+mnDockBottom;
547 vcl::Window *pDockingArea = GetWindow()->GetParent();
548 vcl::Window::PointerState aState = pDockingArea->GetPointerState();
550 // mouse pos in screen pixels
551 Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos );
552 Point aDockPos = pDockingArea->AbsoluteScreenToOutputPixel( GetWindow()->OutputToAbsoluteScreenPixel( GetWindow()->GetPosPixel() ) );
553 tools::Rectangle aDockRect( aDockPos, GetWindow()->GetSizePixel() );
554 StartDocking( aMousePos, aDockRect );
556 GetWindow()->ImplUpdateAll();
557 GetWindow()->ImplGetFrameWindow()->ImplUpdateAll();
559 GetWindow()->StartTracking( StartTrackingFlags::KeyMod );
562 void ImplDockingWindowWrapper::Tracking( const TrackingEvent& rTEvt )
564 // used during docking of a currently docked window
565 if ( !mbDocking )
566 return;
568 if ( rTEvt.IsTrackingEnded() )
570 mbDocking = false;
571 GetWindow()->HideTracking();
572 if ( rTEvt.IsTrackingCanceled() )
574 mbDockCanceled = true;
575 EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
576 mbDockCanceled = false;
578 else
579 EndDocking( tools::Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode );
581 // Docking only upon non-synthetic MouseEvents
582 else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() )
584 Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
585 Point aFrameMousePos = GetWindow()->ImplOutputToFrame( aMousePos );
586 Size aFrameSize = GetWindow()->ImplGetFrameWindow()->GetOutputSizePixel();
587 if ( aFrameMousePos.X() < 0 )
588 aFrameMousePos.setX( 0 );
589 if ( aFrameMousePos.Y() < 0 )
590 aFrameMousePos.setY( 0 );
591 if ( aFrameMousePos.X() > aFrameSize.Width()-1 )
592 aFrameMousePos.setX( aFrameSize.Width()-1 );
593 if ( aFrameMousePos.Y() > aFrameSize.Height()-1 )
594 aFrameMousePos.setY( aFrameSize.Height()-1 );
595 aMousePos = GetWindow()->ImplFrameToOutput( aFrameMousePos );
596 aMousePos.AdjustX( -(maMouseOff.X()) );
597 aMousePos.AdjustY( -(maMouseOff.Y()) );
598 Point aPos = GetWindow()->ImplOutputToFrame( aMousePos );
599 tools::Rectangle aTrackRect( aPos, Size( mnTrackWidth, mnTrackHeight ) );
600 tools::Rectangle aCompRect = aTrackRect;
601 aPos.AdjustX(maMouseOff.X() );
602 aPos.AdjustY(maMouseOff.Y() );
604 bool bFloatMode = Docking( aPos, aTrackRect );
606 if ( mbLastFloatMode != bFloatMode )
608 if ( bFloatMode )
610 aTrackRect.AdjustLeft( -mnDockLeft );
611 aTrackRect.AdjustTop( -mnDockTop );
612 aTrackRect.AdjustRight(mnDockRight );
613 aTrackRect.AdjustBottom(mnDockBottom );
615 else
617 if ( aCompRect == aTrackRect )
619 aTrackRect.AdjustLeft(mnDockLeft );
620 aTrackRect.AdjustTop(mnDockTop );
621 aTrackRect.AdjustRight( -mnDockRight );
622 aTrackRect.AdjustBottom( -mnDockBottom );
625 mbLastFloatMode = bFloatMode;
628 ShowTrackFlags nTrackStyle;
629 if ( bFloatMode )
630 nTrackStyle = ShowTrackFlags::Object;
631 else
632 nTrackStyle = ShowTrackFlags::Big;
633 tools::Rectangle aShowTrackRect = aTrackRect;
634 aShowTrackRect.SetPos( GetWindow()->ImplFrameToOutput( aShowTrackRect.TopLeft() ) );
636 GetWindow()->ShowTracking( aShowTrackRect, nTrackStyle );
638 // calculate mouse offset again, as the rectangle was changed
639 maMouseOff.setX( aPos.X() - aTrackRect.Left() );
640 maMouseOff.setY( aPos.Y() - aTrackRect.Top() );
642 mnTrackX = aTrackRect.Left();
643 mnTrackY = aTrackRect.Top();
644 mnTrackWidth = aTrackRect.GetWidth();
645 mnTrackHeight = aTrackRect.GetHeight();
649 void ImplDockingWindowWrapper::StartDocking( const Point& rPoint, tools::Rectangle const & rRect )
651 DockingData data( rPoint, rRect, IsFloatingMode() );
653 GetWindow()->CallEventListeners( VclEventId::WindowStartDocking, &data );
654 mbDocking = true;
657 bool ImplDockingWindowWrapper::Docking( const Point& rPoint, tools::Rectangle& rRect )
659 DockingData data( rPoint, rRect, IsFloatingMode() );
661 GetWindow()->CallEventListeners( VclEventId::WindowDocking, &data );
662 rRect = data.maTrackRect;
663 return data.mbFloating;
666 void ImplDockingWindowWrapper::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
668 tools::Rectangle aRect( rRect );
670 bool bOrigDockCanceled = mbDockCanceled;
671 if (bFloatMode && !StyleSettings::GetDockingFloatsSupported())
672 mbDockCanceled = true;
674 if ( !IsDockingCanceled() )
676 bool bShow = false;
677 if ( bFloatMode != IsFloatingMode() )
679 GetWindow()->Show( false, ShowFlags::NoFocusChange );
680 SetFloatingMode( bFloatMode );
681 bShow = true;
682 if ( bFloatMode )
684 // #i44800# always use outputsize - as in all other places
685 mpFloatWin->SetOutputSizePixel( aRect.GetSize() );
686 mpFloatWin->SetPosPixel( aRect.TopLeft() );
689 if ( !bFloatMode )
691 Point aPos = aRect.TopLeft();
692 aPos = GetWindow()->GetParent()->ScreenToOutputPixel( aPos );
693 GetWindow()->SetPosSizePixel( aPos, aRect.GetSize() );
696 if ( bShow )
697 GetWindow()->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
700 EndDockingData data( aRect, IsFloatingMode(), IsDockingCanceled() );
701 GetWindow()->CallEventListeners( VclEventId::WindowEndDocking, &data );
703 mbDocking = false;
705 // must be enabled in Window::Notify to prevent permanent docking during mouse move
706 mbStartDockingEnabled = false;
708 mbDockCanceled = bOrigDockCanceled;
711 bool ImplDockingWindowWrapper::PrepareToggleFloatingMode()
713 bool bFloating = true;
714 GetWindow()->CallEventListeners( VclEventId::WindowPrepareToggleFloating, &bFloating );
715 return bFloating;
718 void ImplDockingWindowWrapper::ToggleFloatingMode()
720 // notify dockingwindow/toolbox
721 // note: this must be done *before* notifying the
722 // listeners to have the toolbox in the proper state
723 if( GetWindow()->IsDockingWindow() )
724 static_cast<DockingWindow*>(GetWindow())->ToggleFloatingMode();
726 // now notify listeners
727 GetWindow()->CallEventListeners( VclEventId::WindowToggleFloating );
729 // must be enabled in Window::Notify to prevent permanent docking during mouse move
730 mbStartDockingEnabled = false;
733 void ImplDockingWindowWrapper::TitleButtonClick( TitleButton nType )
735 if( nType == TitleButton::Menu )
737 ToolBox *pToolBox = dynamic_cast< ToolBox* >( GetWindow() );
738 if( pToolBox )
740 pToolBox->ExecuteCustomMenu();
743 if( nType == TitleButton::Docking )
745 SetFloatingMode( !IsFloatingMode() );
749 void ImplDockingWindowWrapper::Resizing( Size& rSize )
751 // TODO: add virtual Resizing() to class Window, so we can get rid of class DockingWindow
752 DockingWindow *pDockingWindow = dynamic_cast< DockingWindow* >( GetWindow() );
753 if( pDockingWindow )
754 pDockingWindow->Resizing( rSize );
757 void ImplDockingWindowWrapper::ShowMenuTitleButton( bool bVisible )
759 if ( mpFloatWin )
760 mpFloatWin->ShowTitleButton( TitleButton::Menu, bVisible );
763 void ImplDockingWindowWrapper::ImplPreparePopupMode()
765 VclPtr<vcl::Window> xWindow = GetWindow();
766 xWindow->Show( false, ShowFlags::NoFocusChange );
768 // prepare reparenting
769 vcl::Window* pRealParent = xWindow->GetWindow( GetWindowType::Parent );
770 mpOldBorderWin = xWindow->GetWindow( GetWindowType::Border );
771 if( mpOldBorderWin.get() == xWindow )
772 mpOldBorderWin = nullptr; // no border window found
774 // the new parent for popup mode
775 VclPtrInstance<ImplPopupFloatWin> pWin( mpParent, xWindow->GetType() == WindowType::TOOLBOX );
776 pWin->SetPopupModeEndHdl( LINK( this, ImplDockingWindowWrapper, PopupModeEnd ) );
778 // At least for DockingWindow, GetText() has a side effect of setting deferred
779 // properties. This must be done before setting the border window (see below),
780 // so that the border width will end up in mpWindowImpl->mnBorderWidth, not in
781 // the border window (See DockingWindow::setPosSizeOnContainee() and
782 // DockingWindow::GetOptimalSize()).
783 pWin->SetText( xWindow->GetText() );
784 pWin->SetOutputSizePixel( xWindow->GetSizePixel() );
786 xWindow->mpWindowImpl->mpBorderWindow = nullptr;
787 xWindow->mpWindowImpl->mnLeftBorder = 0;
788 xWindow->mpWindowImpl->mnTopBorder = 0;
789 xWindow->mpWindowImpl->mnRightBorder = 0;
790 xWindow->mpWindowImpl->mnBottomBorder = 0;
792 // reparent borderwindow and window
793 if ( mpOldBorderWin )
794 mpOldBorderWin->SetParent( pWin );
795 xWindow->SetParent( pWin );
797 // correct border window pointers
798 xWindow->mpWindowImpl->mpBorderWindow = pWin;
799 pWin->mpWindowImpl->mpClientWindow = xWindow;
800 xWindow->mpWindowImpl->mpRealParent = pRealParent;
802 // set mpFloatWin not until all window positioning is done !!!
803 // (SetPosPixel etc. check for valid mpFloatWin pointer)
804 mpFloatWin = pWin;
807 void ImplDockingWindowWrapper::StartPopupMode( ToolBox *pParentToolBox, FloatWinPopupFlags nFlags )
809 // do nothing if window is floating
810 if( IsFloatingMode() )
811 return;
813 ImplPreparePopupMode();
815 // don't allow tearoff, if globally disabled
816 if( !StyleSettings::GetDockingFloatsSupported() )
817 nFlags &= ~FloatWinPopupFlags::AllowTearOff;
819 // if the subtoolbar was opened via keyboard make sure that key events
820 // will go into subtoolbar
821 if( pParentToolBox->IsKeyEvent() )
822 nFlags |= FloatWinPopupFlags::GrabFocus;
824 // tdf#140762, tdf#152671, tdf#154470, tdf#156100: Without client window being visible
825 // before showing popup, at least NVDA on Windows does not announce items in the popup,
826 // so make the client window visible first. This is problematic for gtk VCL plugins though,
827 // so don't do it there and use different code paths for now.
828 // For further analysis of the root causes, there's tdf#156561.
829 const OUString sToolkit = Application::GetToolkitName();
830 if (sToolkit == "gtk3" || sToolkit == "gtk4")
832 mpFloatWin->StartPopupMode( pParentToolBox, nFlags);
833 GetWindow()->Show();
835 else
837 mpFloatWin->StartPopupMode( pParentToolBox, nFlags | FloatWinPopupFlags::MakeClientWindowVisibleBeforePopup);
840 if( pParentToolBox->IsKeyEvent() )
842 // send HOME key to subtoolbar in order to select first item
843 KeyEvent aEvent( 0, vcl::KeyCode( KEY_HOME ) );
844 GetWindow()->KeyInput(aEvent);
848 void ImplDockingWindowWrapper::StartPopupMode( const tools::Rectangle& rRect, FloatWinPopupFlags nFlags )
850 // do nothing if window is floating
851 if( IsFloatingMode() )
852 return;
854 ImplPreparePopupMode();
855 mpFloatWin->StartPopupMode( rRect, nFlags | FloatWinPopupFlags::MakeClientWindowVisibleBeforePopup);
858 IMPL_LINK_NOARG(ImplDockingWindowWrapper, PopupModeEnd, FloatingWindow*, void)
860 VclPtr<vcl::Window> xWindow = GetWindow();
861 xWindow->Show( false, ShowFlags::NoFocusChange );
863 // set parameter for handler before destroying floating window
864 EndPopupModeData aData( mpFloatWin->GetWindow( GetWindowType::Border )->GetPosPixel(), mpFloatWin->IsPopupModeTearOff() );
866 // before deleting change parent back, so we can delete the floating window alone
867 vcl::Window* pRealParent = xWindow->GetWindow( GetWindowType::Parent );
868 xWindow->mpWindowImpl->mpBorderWindow = nullptr;
869 if ( mpOldBorderWin )
871 xWindow->SetParent( mpOldBorderWin );
872 static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder(
873 xWindow->mpWindowImpl->mnLeftBorder, xWindow->mpWindowImpl->mnTopBorder,
874 xWindow->mpWindowImpl->mnRightBorder, xWindow->mpWindowImpl->mnBottomBorder );
875 mpOldBorderWin->Resize();
877 xWindow->mpWindowImpl->mpBorderWindow = mpOldBorderWin;
878 xWindow->SetParent( pRealParent );
879 xWindow->mpWindowImpl->mpRealParent = pRealParent;
881 // take ownership to local variable to protect against maPopupModeEndHdl destroying this object
882 auto xFloatWin = std::move(mpFloatWin);
883 maPopupModeEndHdl.Call(xFloatWin);
884 xFloatWin.disposeAndClear();
886 // call handler - which will destroy the window and thus the wrapper as well !
887 xWindow->CallEventListeners( VclEventId::WindowEndPopupMode, &aData );
890 bool ImplDockingWindowWrapper::IsInPopupMode() const
892 if( GetFloatingWindow() )
893 return static_cast<FloatingWindow*>(GetFloatingWindow())->IsInPopupMode();
894 else
895 return false;
898 void ImplDockingWindowWrapper::SetFloatingMode( bool bFloatMode )
900 // do nothing if window is docked and locked
901 if( !IsFloatingMode() && IsLocked() )
902 return;
904 if ( IsFloatingMode() == bFloatMode )
905 return;
907 if ( !PrepareToggleFloatingMode() )
908 return;
910 bool bVisible = GetWindow()->IsVisible();
912 if ( bFloatMode )
914 GetWindow()->Show( false, ShowFlags::NoFocusChange );
916 maDockPos = GetWindow()->GetPosPixel();
918 vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent );
919 mpOldBorderWin = GetWindow()->GetWindow( GetWindowType::Border );
920 if( mpOldBorderWin == mpDockingWindow )
921 mpOldBorderWin = nullptr; // no border window found
923 VclPtrInstance<ImplDockFloatWin2> pWin(
924 mpParent,
925 mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ?
926 mnFloatBits | WB_SYSTEMWINDOW
927 | WB_OWNERDRAWDECORATION
928 : mnFloatBits,
929 this );
931 // At least for DockingWindow, GetText() has a side effect of setting deferred
932 // properties. This must be done before setting the border window (see below),
933 // so that the border width will end up in mpWindowImpl->mnBorderWidth, not in
934 // the border window (See DockingWindow::setPosSizeOnContainee() and
935 // DockingWindow::GetOptimalSize()).
936 pWin->SetText( GetWindow()->GetText() );
938 GetWindow()->mpWindowImpl->mpBorderWindow = nullptr;
939 GetWindow()->mpWindowImpl->mnLeftBorder = 0;
940 GetWindow()->mpWindowImpl->mnTopBorder = 0;
941 GetWindow()->mpWindowImpl->mnRightBorder = 0;
942 GetWindow()->mpWindowImpl->mnBottomBorder = 0;
944 // if the parent gets destroyed, we also have to reset the parent of the BorderWindow
945 if ( mpOldBorderWin )
946 mpOldBorderWin->SetParent( pWin );
947 GetWindow()->SetParent( pWin );
948 pWin->SetPosPixel( Point() );
950 GetWindow()->mpWindowImpl->mpBorderWindow = pWin;
951 pWin->mpWindowImpl->mpClientWindow = mpDockingWindow;
952 GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
954 pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() );
955 pWin->SetPosPixel( maFloatPos );
956 // pass on DockingData to FloatingWindow
957 pWin->ShowTitleButton( TitleButton::Docking, mbDockBtn );
958 pWin->ShowTitleButton( TitleButton::Hide, mbHideBtn );
959 pWin->SetMinOutputSizePixel( maMinOutSize );
960 pWin->SetMaxOutputSizePixel( maMaxOutSize );
962 mpFloatWin = pWin;
964 if ( bVisible )
965 GetWindow()->Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
967 ToggleFloatingMode();
969 else
971 GetWindow()->Show( false, ShowFlags::NoFocusChange );
973 // store FloatingData in FloatingWindow
974 maFloatPos = mpFloatWin->GetPosPixel();
975 mbDockBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Docking );
976 mbHideBtn = mpFloatWin->IsTitleButtonVisible( TitleButton::Hide );
977 maMinOutSize = mpFloatWin->GetMinOutputSizePixel();
978 maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel();
980 vcl::Window* pRealParent = GetWindow()->GetWindow( GetWindowType::Parent ); //mpWindowImpl->mpRealParent;
981 GetWindow()->mpWindowImpl->mpBorderWindow = nullptr;
982 if ( mpOldBorderWin )
984 GetWindow()->SetParent( mpOldBorderWin );
985 static_cast<ImplBorderWindow*>(mpOldBorderWin.get())->GetBorder(
986 GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder,
987 GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder );
988 mpOldBorderWin->Resize();
990 GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin;
991 GetWindow()->SetParent( pRealParent );
992 GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
994 mpFloatWin.disposeAndClear();
995 GetWindow()->SetPosPixel( maDockPos );
997 if ( bVisible )
998 GetWindow()->Show();
1000 ToggleFloatingMode();
1005 void ImplDockingWindowWrapper::SetFloatStyle( WinBits nStyle )
1007 mnFloatBits = nStyle;
1011 void ImplDockingWindowWrapper::setPosSizePixel( tools::Long nX, tools::Long nY,
1012 tools::Long nWidth, tools::Long nHeight,
1013 PosSizeFlags nFlags )
1015 if ( mpFloatWin )
1016 mpFloatWin->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
1017 else
1018 GetWindow()->setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
1021 Point ImplDockingWindowWrapper::GetPosPixel() const
1023 if ( mpFloatWin )
1024 return mpFloatWin->GetPosPixel();
1025 else
1026 return mpDockingWindow->GetPosPixel();
1029 Size ImplDockingWindowWrapper::GetSizePixel() const
1031 if ( mpFloatWin )
1032 return mpFloatWin->GetSizePixel();
1033 else
1034 return mpDockingWindow->GetSizePixel();
1037 // old inlines from DockingWindow
1039 void ImplDockingWindowWrapper::SetMinOutputSizePixel( const Size& rSize )
1041 if ( mpFloatWin )
1042 mpFloatWin->SetMinOutputSizePixel( rSize );
1043 maMinOutSize = rSize;
1046 void ImplDockingWindowWrapper::SetMaxOutputSizePixel( const Size& rSize )
1048 if ( mpFloatWin )
1049 mpFloatWin->SetMaxOutputSizePixel( rSize );
1050 maMaxOutSize = rSize;
1053 bool ImplDockingWindowWrapper::IsFloatingMode() const
1055 return (mpFloatWin != nullptr);
1058 void ImplDockingWindowWrapper::SetDragArea( const tools::Rectangle& rRect )
1060 maDragArea = rRect;
1064 void ImplDockingWindowWrapper::Lock()
1066 mbLocked = true;
1067 // only toolbars support locking
1068 ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() );
1069 if( pToolBox )
1070 pToolBox->Lock( mbLocked );
1073 void ImplDockingWindowWrapper::Unlock()
1075 mbLocked = false;
1076 // only toolbars support locking
1077 ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() );
1078 if( pToolBox )
1079 pToolBox->Lock( mbLocked );
1082 SystemWindow* ImplDockingWindowWrapper::GetFloatingWindow() const
1084 return mpFloatWin;
1087 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */