lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / vcl / source / window / floatwin.cxx
blob9de1efdaf221f0ebf3a6f722e4972ad93662efe7
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 <svdata.hxx>
21 #include <brdwin.hxx>
22 #include <window.h>
23 #include <salframe.hxx>
25 #include <comphelper/lok.hxx>
26 #include <sal/log.hxx>
27 #include <vcl/layout.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/wrkwin.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/toolbox.hxx>
32 #include <vcl/floatwin.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/IDialogRenderable.hxx>
36 class FloatingWindow::ImplData
38 public:
39 ImplData();
41 VclPtr<ToolBox> mpBox;
42 tools::Rectangle maItemEdgeClipRect; // used to clip the common edge between a toolbar item and the border of this window
43 Point maPos; // position of the floating window wrt. parent
44 Point maLOKTwipsPos; ///< absolute position of the floating window in the document - in twips (for toplevel floating windows).
47 FloatingWindow::ImplData::ImplData()
49 mpBox = nullptr;
52 tools::Rectangle& FloatingWindow::ImplGetItemEdgeClipRect()
54 return mpImplData->maItemEdgeClipRect;
57 void FloatingWindow::ImplInit( vcl::Window* pParent, WinBits nStyle )
59 mpImplData.reset(new ImplData);
61 mpWindowImpl->mbFloatWin = true;
62 mbInCleanUp = false;
63 mbGrabFocus = false;
65 SAL_WARN_IF(!pParent, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL!");
67 if (!pParent)
68 pParent = ImplGetSVData()->maFrameData.mpAppWin;
70 SAL_WARN_IF(!pParent, "vcl", "FloatWindow::FloatingWindow(): - pParent == NULL and no AppWindow exists");
72 // no Border, then we don't need a border window
73 if (!nStyle)
75 mpWindowImpl->mbOverlapWin = true;
76 nStyle |= WB_DIALOGCONTROL;
77 SystemWindow::ImplInit(pParent, nStyle, nullptr);
79 else
81 if (!(nStyle & WB_NODIALOGCONTROL))
82 nStyle |= WB_DIALOGCONTROL;
84 if (nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE)
85 && !(nStyle & WB_OWNERDRAWDECORATION))
87 WinBits nFloatWinStyle = nStyle;
88 // #99154# floaters are not closeable by default anymore, eg fullscreen floater
89 // nFloatWinStyle |= WB_CLOSEABLE;
90 mpWindowImpl->mbFrame = true;
91 mpWindowImpl->mbOverlapWin = true;
92 SystemWindow::ImplInit(pParent, nFloatWinStyle & ~WB_BORDER, nullptr);
94 else
96 VclPtr<ImplBorderWindow> pBorderWin;
97 BorderWindowStyle nBorderStyle = BorderWindowStyle::Border | BorderWindowStyle::Float;
99 if (nStyle & WB_OWNERDRAWDECORATION)
100 nBorderStyle |= BorderWindowStyle::Frame;
101 else
102 nBorderStyle |= BorderWindowStyle::Overlap;
104 if ((nStyle & WB_SYSTEMWINDOW) && !(nStyle & (WB_MOVEABLE | WB_SIZEABLE)))
106 nBorderStyle |= BorderWindowStyle::Frame;
107 nStyle |= WB_CLOSEABLE; // make undecorated floaters closeable
109 pBorderWin = VclPtr<ImplBorderWindow>::Create(pParent, nStyle, nBorderStyle);
110 SystemWindow::ImplInit(pBorderWin, nStyle & ~WB_BORDER, nullptr);
111 pBorderWin->mpWindowImpl->mpClientWindow = this;
112 pBorderWin->GetBorder(mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder,
113 mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder);
114 pBorderWin->SetDisplayActive(true);
115 mpWindowImpl->mpBorderWindow = pBorderWin;
116 mpWindowImpl->mpRealParent = pParent;
119 SetActivateMode( ActivateModeFlags::NONE );
121 mpNextFloat = nullptr;
122 mpFirstPopupModeWin = nullptr;
123 mnPostId = nullptr;
124 mnTitle = (nStyle & (WB_MOVEABLE | WB_POPUP)) ? FloatWinTitleType::Normal : FloatWinTitleType::NONE;
125 mnOldTitle = mnTitle;
126 mnPopupModeFlags = FloatWinPopupFlags::NONE;
127 mbInPopupMode = false;
128 mbPopupMode = false;
129 mbPopupModeCanceled = false;
130 mbPopupModeTearOff = false;
131 mbMouseDown = false;
133 ImplInitSettings();
136 void FloatingWindow::ImplInitSettings()
138 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
140 Color aColor;
141 if (IsControlBackground())
142 aColor = GetControlBackground();
143 else if (Window::GetStyle() & WB_3DLOOK)
144 aColor = rStyleSettings.GetFaceColor();
145 else
146 aColor = rStyleSettings.GetWindowColor();
147 SetBackground(aColor);
150 FloatingWindow::FloatingWindow(vcl::Window* pParent, WinBits nStyle) :
151 SystemWindow(WindowType::FLOATINGWINDOW)
153 ImplInit(pParent, nStyle);
156 FloatingWindow::FloatingWindow(vcl::Window* pParent, const OString& rID, const OUString& rUIXMLDescription, const css::uno::Reference<css::frame::XFrame> &rFrame)
157 : SystemWindow(WindowType::FLOATINGWINDOW)
158 , mpNextFloat(nullptr)
159 , mpFirstPopupModeWin(nullptr)
160 , mnPostId(nullptr)
161 , mnPopupModeFlags(FloatWinPopupFlags::NONE)
162 , mnTitle(FloatWinTitleType::Unknown)
163 , mnOldTitle(FloatWinTitleType::Unknown)
164 , mbInPopupMode(false)
165 , mbPopupMode(false)
166 , mbPopupModeCanceled(false)
167 , mbPopupModeTearOff(false)
168 , mbMouseDown(false)
169 , mbGrabFocus(false)
170 , mbInCleanUp(false)
172 loadUI(pParent, rID, rUIXMLDescription, rFrame);
175 //Find the real parent stashed in mpDialogParent.
176 void FloatingWindow::doDeferredInit(WinBits nBits)
178 vcl::Window *pParent = mpDialogParent;
179 mpDialogParent = nullptr;
180 ImplInit(pParent, nBits);
181 mbIsDeferredInit = false;
184 void FloatingWindow::ApplySettings(vcl::RenderContext& rRenderContext)
186 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
188 Color aColor;
189 if (Window::GetStyle() & WB_3DLOOK)
190 aColor = rStyleSettings.GetFaceColor();
191 else
192 aColor = rStyleSettings.GetWindowColor();
194 ApplyControlBackground(rRenderContext, aColor);
197 FloatingWindow::~FloatingWindow()
199 disposeOnce();
200 assert (!mnPostId);
203 void FloatingWindow::dispose()
205 ReleaseLOKNotifier();
207 if (mpImplData)
209 if( mbPopupModeCanceled )
210 // indicates that ESC key was pressed
211 // will be handled in Window::ImplGrabFocus()
212 SetDialogControlFlags( GetDialogControlFlags() | DialogControlFlags::FloatWinPopupModeEndCancel );
214 if ( IsInPopupMode() )
215 EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll | FloatWinPopupEndFlags::DontCallHdl );
217 if ( mnPostId )
218 Application::RemoveUserEvent( mnPostId );
219 mnPostId = nullptr;
222 mpImplData.reset();
224 mpNextFloat.clear();
225 mpFirstPopupModeWin.clear();
226 mxPrevFocusWin.clear();
227 SystemWindow::dispose();
230 Point FloatingWindow::CalcFloatingPosition( vcl::Window* pWindow, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags, sal_uInt16& rArrangeIndex )
232 return ImplCalcPos( pWindow, rRect, nFlags, rArrangeIndex );
235 Point FloatingWindow::ImplCalcPos(vcl::Window* pWindow,
236 const tools::Rectangle& rRect, FloatWinPopupFlags nFlags,
237 sal_uInt16& rArrangeIndex, Point* pLOKTwipsPos)
239 // get window position
240 Point aPos;
241 Size aSize = ::isLayoutEnabled(pWindow) ? pWindow->get_preferred_size() : pWindow->GetSizePixel();
242 tools::Rectangle aScreenRect = pWindow->ImplGetFrameWindow()->GetDesktopRectPixel();
243 FloatingWindow *pFloatingWindow = dynamic_cast<FloatingWindow*>( pWindow );
245 // convert....
246 vcl::Window* pW = pWindow;
247 if ( pW->mpWindowImpl->mpRealParent )
248 pW = pW->mpWindowImpl->mpRealParent;
250 tools::Rectangle normRect( rRect ); // rRect is already relative to top-level window
251 normRect.SetPos( pW->ScreenToOutputPixel( normRect.TopLeft() ) );
253 bool bRTL = AllSettings::GetLayoutRTL();
255 tools::Rectangle devRect( pW->OutputToAbsoluteScreenPixel( normRect.TopLeft() ),
256 pW->OutputToAbsoluteScreenPixel( normRect.BottomRight() ) );
258 tools::Rectangle devRectRTL( devRect );
259 if( bRTL )
260 // create a rect that can be compared to desktop coordinates
261 devRectRTL = pW->ImplOutputToUnmirroredAbsoluteScreenPixel( normRect );
262 if( Application::GetScreenCount() > 1 && Application::IsUnifiedDisplay() )
263 aScreenRect = Application::GetScreenPosSizePixel(
264 Application::GetBestScreen( bRTL ? devRectRTL : devRect ) );
266 FloatWinPopupFlags nArrangeAry[5];
267 Point e1,e2; // the common edge between the item rect and the floating window
269 if ( nFlags & FloatWinPopupFlags::Left )
271 nArrangeAry[0] = FloatWinPopupFlags::Left;
272 nArrangeAry[1] = FloatWinPopupFlags::Right;
273 nArrangeAry[2] = FloatWinPopupFlags::Up;
274 nArrangeAry[3] = FloatWinPopupFlags::Down;
275 nArrangeAry[4] = FloatWinPopupFlags::Left;
277 else if ( nFlags & FloatWinPopupFlags::Right )
279 nArrangeAry[0] = FloatWinPopupFlags::Right;
280 nArrangeAry[1] = FloatWinPopupFlags::Left;
281 nArrangeAry[2] = FloatWinPopupFlags::Up;
282 nArrangeAry[3] = FloatWinPopupFlags::Down;
283 nArrangeAry[4] = FloatWinPopupFlags::Right;
285 else if ( nFlags & FloatWinPopupFlags::Up )
287 nArrangeAry[0] = FloatWinPopupFlags::Up;
288 nArrangeAry[1] = FloatWinPopupFlags::Down;
289 nArrangeAry[2] = FloatWinPopupFlags::Right;
290 nArrangeAry[3] = FloatWinPopupFlags::Left;
291 nArrangeAry[4] = FloatWinPopupFlags::Up;
293 else
295 nArrangeAry[0] = FloatWinPopupFlags::Down;
296 nArrangeAry[1] = FloatWinPopupFlags::Up;
297 nArrangeAry[2] = FloatWinPopupFlags::Right;
298 nArrangeAry[3] = FloatWinPopupFlags::Left;
299 nArrangeAry[4] = FloatWinPopupFlags::Down;
302 sal_uInt16 nArrangeIndex = 0;
303 const bool bLOKActive = comphelper::LibreOfficeKit::isActive();
305 for ( ; nArrangeIndex < 5; nArrangeIndex++ )
307 bool bBreak = true;
308 switch ( nArrangeAry[nArrangeIndex] )
311 case FloatWinPopupFlags::Left:
312 aPos.setX( devRect.Left()-aSize.Width()+1 );
313 aPos.setY( devRect.Top() );
314 aPos.AdjustY( -(pWindow->mpWindowImpl->mnTopBorder) );
315 if( bRTL )
317 if( (devRectRTL.Right()+aSize.Width()) > aScreenRect.Right() )
318 bBreak = false;
320 else
322 if ( aPos.X() < aScreenRect.Left() )
323 bBreak = false;
325 if (bBreak || bLOKActive)
327 e1 = devRect.TopLeft();
328 e2 = devRect.BottomLeft();
329 // set non-zero width
330 e2.AdjustX( 1 );
331 // don't clip corners
332 e1.AdjustY( 1 );
333 e2.AdjustY( -1 );
335 break;
336 case FloatWinPopupFlags::Right:
337 aPos = devRect.TopRight();
338 aPos.AdjustY( -(pWindow->mpWindowImpl->mnTopBorder) );
339 if( bRTL )
341 if( (devRectRTL.Left() - aSize.Width()) < aScreenRect.Left() )
342 bBreak = false;
344 else
346 if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
347 bBreak = false;
349 if (bBreak || bLOKActive)
351 e1 = devRect.TopRight();
352 e2 = devRect.BottomRight();
353 // set non-zero width
354 e2.AdjustX( 1 );
355 // don't clip corners
356 e1.AdjustY( 1 );
357 e2.AdjustY( -1 );
359 break;
360 case FloatWinPopupFlags::Up:
361 aPos.setX( devRect.Left() );
362 aPos.setY( devRect.Top()-aSize.Height()+1 );
363 if ( aPos.Y() < aScreenRect.Top() )
364 bBreak = false;
365 if (bBreak || bLOKActive)
367 e1 = devRect.TopLeft();
368 e2 = devRect.TopRight();
369 // set non-zero height
370 e2.AdjustY( 1 );
371 // don't clip corners
372 e1.AdjustX( 1 );
373 e2.AdjustX( -1 );
375 break;
376 case FloatWinPopupFlags::Down:
377 aPos = devRect.BottomLeft();
378 if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
379 bBreak = false;
380 if (bBreak || bLOKActive)
382 e1 = devRect.BottomLeft();
383 e2 = devRect.BottomRight();
384 // set non-zero height
385 e2.AdjustY( 1 );
386 // don't clip corners
387 e1.AdjustX( 1 );
388 e2.AdjustX( -1 );
390 break;
391 default: break;
394 // no further adjustement for LibreOfficeKit
395 if (bLOKActive)
396 break;
398 // adjust if necessary
399 if (bBreak)
401 if ( (nArrangeAry[nArrangeIndex] == FloatWinPopupFlags::Left) ||
402 (nArrangeAry[nArrangeIndex] == FloatWinPopupFlags::Right) )
404 if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() )
406 aPos.setY( devRect.Bottom()-aSize.Height()+1 );
407 if ( aPos.Y() < aScreenRect.Top() )
408 aPos.setY( aScreenRect.Top() );
411 else
413 if( bRTL )
415 if( devRectRTL.Right()-aSize.Width()+1 < aScreenRect.Left() )
416 aPos.AdjustX( -(aScreenRect.Left() - devRectRTL.Right() + aSize.Width() - 1) );
418 else if ( aPos.X()+aSize.Width() > aScreenRect.Right() )
420 aPos.setX( devRect.Right()-aSize.Width()+1 );
421 if ( aPos.X() < aScreenRect.Left() )
422 aPos.setX( aScreenRect.Left() );
427 if ( bBreak )
428 break;
430 if ( nArrangeIndex > 4 )
431 nArrangeIndex = 4;
433 rArrangeIndex = nArrangeIndex;
435 aPos = pW->AbsoluteScreenToOutputPixel( aPos );
437 // store a cliprect that can be used to clip the common edge of the itemrect and the floating window
438 if( pFloatingWindow && pFloatingWindow->mpImplData->mpBox )
440 pFloatingWindow->mpImplData->maItemEdgeClipRect =
441 tools::Rectangle( e1, e2 );
444 if (bLOKActive && pLOKTwipsPos)
446 if (pW->IsMapModeEnabled() || pW->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
448 // if we use pW->LogicToLogic(aPos, pW->GetMapMode(), MapMode(MapUnit::MapTwip)),
449 // for pixel conversions when map mode is not enabled, we gets
450 // a 20 twips per pixel conversion since LogicToLogic uses
451 // a fixed 72 dpi value, instead of a correctly computed output
452 // device dpi or at least the most commonly used 96 dpi value;
453 // and anyway the following is what we already do in
454 // ScGridWindow::LogicInvalidate when map mode is not enabled.
456 *pLOKTwipsPos = pW->PixelToLogic(aPos, MapMode(MapUnit::MapTwip));
458 else
460 *pLOKTwipsPos = OutputDevice::LogicToLogic(aPos, pW->GetMapMode(), MapMode(MapUnit::MapTwip));
464 // caller expects coordinates relative to top-level win
465 return pW->OutputToScreenPixel( aPos );
468 Point FloatingWindow::ImplConvertToAbsPos(vcl::Window* pReference, const Point& rPos)
470 Point aAbsolute( rPos );
472 const OutputDevice *pWindowOutDev = pReference->GetOutDev();
474 // compare coordinates in absolute screen coordinates
475 if( pReference->HasMirroredGraphics() )
477 if(!pReference->IsRTLEnabled() )
478 pWindowOutDev->ReMirror( aAbsolute );
480 tools::Rectangle aRect( pReference->ScreenToOutputPixel(aAbsolute), Size(1,1) ) ;
481 aRect = pReference->ImplOutputToUnmirroredAbsoluteScreenPixel( aRect );
482 aAbsolute = aRect.TopLeft();
484 else
485 aAbsolute = pReference->OutputToAbsoluteScreenPixel(
486 pReference->ScreenToOutputPixel(rPos) );
488 return aAbsolute;
491 tools::Rectangle FloatingWindow::ImplConvertToAbsPos(vcl::Window* pReference, const tools::Rectangle& rRect)
493 tools::Rectangle aFloatRect = rRect;
495 const OutputDevice *pParentWinOutDev = pReference->GetOutDev();
497 // compare coordinates in absolute screen coordinates
498 // Keep in sync with FloatingWindow::ImplFloatHitTest, e.g. fdo#33509
499 if( pReference->HasMirroredGraphics() )
501 if(!pReference->IsRTLEnabled() )
502 pParentWinOutDev->ReMirror(aFloatRect);
504 aFloatRect.SetPos(pReference->ScreenToOutputPixel(aFloatRect.TopLeft()));
505 aFloatRect = pReference->ImplOutputToUnmirroredAbsoluteScreenPixel(aFloatRect);
507 else
508 aFloatRect.SetPos(pReference->OutputToAbsoluteScreenPixel(pReference->ScreenToOutputPixel(rRect.TopLeft())));
509 return aFloatRect;
512 FloatingWindow* FloatingWindow::ImplFloatHitTest( vcl::Window* pReference, const Point& rPos, HitTest& rHitTest )
514 FloatingWindow* pWin = this;
516 Point aAbsolute(FloatingWindow::ImplConvertToAbsPos(pReference, rPos));
520 // compute the floating window's size in absolute screen coordinates
522 // use the border window to have the exact position
523 vcl::Window *pBorderWin = pWin->GetWindow( GetWindowType::Border );
525 // the top-left corner in output coordinates ie (0,0)
526 tools::Rectangle devRect( pBorderWin->ImplOutputToUnmirroredAbsoluteScreenPixel( tools::Rectangle( Point(), pBorderWin->GetSizePixel()) ) ) ;
527 if ( devRect.IsInside( aAbsolute ) )
529 rHitTest = HITTEST_WINDOW;
530 return pWin;
533 // test, if mouse is in rectangle, (this is typically the rect of the active
534 // toolbox item or similar)
535 // note: maFloatRect is set in FloatingWindow::StartPopupMode() and
536 // is already in absolute device coordinates
537 if ( pWin->maFloatRect.IsInside( aAbsolute ) )
539 rHitTest = HITTEST_RECT;
540 return pWin;
543 pWin = pWin->mpNextFloat;
545 while ( pWin );
547 rHitTest = HITTEST_OUTSIDE;
548 return nullptr;
551 FloatingWindow* FloatingWindow::ImplFindLastLevelFloat()
553 FloatingWindow* pWin = this;
554 FloatingWindow* pLastFoundWin = pWin;
558 if ( pWin->GetPopupModeFlags() & FloatWinPopupFlags::NewLevel )
559 pLastFoundWin = pWin;
561 pWin = pWin->mpNextFloat;
563 while ( pWin );
565 return pLastFoundWin;
568 bool FloatingWindow::ImplIsFloatPopupModeWindow( const vcl::Window* pWindow )
570 FloatingWindow* pWin = this;
574 if ( pWin->mpFirstPopupModeWin == pWindow )
575 return true;
577 pWin = pWin->mpNextFloat;
579 while ( pWin );
581 return false;
584 IMPL_LINK_NOARG(FloatingWindow, ImplEndPopupModeHdl, void*, void)
586 VclPtr<FloatingWindow> pThis(this);
587 mnPostId = nullptr;
588 mnPopupModeFlags = FloatWinPopupFlags::NONE;
589 mbPopupMode = false;
590 PopupModeEnd();
593 bool FloatingWindow::EventNotify( NotifyEvent& rNEvt )
595 // call Base Class first for tab control
596 bool bRet = SystemWindow::EventNotify( rNEvt );
597 if ( !bRet )
599 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
601 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
602 vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
603 sal_uInt16 nKeyCode = aKeyCode.GetCode();
605 if ( (nKeyCode == KEY_ESCAPE) && (GetStyle() & WB_CLOSEABLE) )
607 Close();
608 return true;
613 return bRet;
616 void FloatingWindow::PixelInvalidate(const tools::Rectangle* /*pRectangle*/)
618 if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
620 std::vector<vcl::LOKPayloadItem> aPayload;
621 const tools::Rectangle aRect(Point(0,0), Size(GetSizePixel().Width()+1, GetSizePixel().Height()+1));
622 aPayload.push_back(std::make_pair(OString("rectangle"), aRect.toString()));
623 const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
624 pNotifier->notifyWindow(GetLOKWindowId(), "invalidate", aPayload);
628 void FloatingWindow::StateChanged( StateChangedType nType )
630 if (nType == StateChangedType::InitShow)
632 DoInitialLayout();
635 SystemWindow::StateChanged( nType );
637 VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier();
638 if (pParent)
640 if (nType == StateChangedType::InitShow)
642 std::vector<vcl::LOKPayloadItem> aItems;
643 if (pParent == this)
645 // we are a toplevel window, let's so far pretend to be a
646 // dialog - but maybe we'll need a separate type for this
647 // later
648 aItems.emplace_back("type", "dialog");
649 aItems.emplace_back("position", mpImplData->maLOKTwipsPos.toString()); // twips
651 else
653 SetLOKNotifier(pParent->GetLOKNotifier());
654 aItems.emplace_back("type", "child");
655 aItems.emplace_back("parentId", OString::number(pParent->GetLOKWindowId()));
656 if (mbInPopupMode)
657 aItems.emplace_back("position", mpImplData->maPos.toString()); // pixels
658 else // mpImplData->maPos is not set
659 aItems.emplace_back("position", GetPosPixel().toString());
662 aItems.emplace_back("size", GetSizePixel().toString());
663 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "created", aItems);
665 else if (!IsVisible() && nType == StateChangedType::Visible)
667 assert(GetLOKNotifier());
668 GetLOKNotifier()->notifyWindow(GetLOKWindowId(), "close");
669 ReleaseLOKNotifier();
673 if ( nType == StateChangedType::ControlBackground )
675 ImplInitSettings();
676 Invalidate();
680 void FloatingWindow::DataChanged( const DataChangedEvent& rDCEvt )
682 SystemWindow::DataChanged( rDCEvt );
684 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
685 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
687 ImplInitSettings();
688 Invalidate();
692 void FloatingWindow::ImplCallPopupModeEnd()
694 // PopupMode is finished
695 mbInPopupMode = false;
697 // call Handler asynchronously.
698 if ( mpImplData && !mnPostId )
699 mnPostId = Application::PostUserEvent(LINK(this, FloatingWindow, ImplEndPopupModeHdl));
702 void FloatingWindow::PopupModeEnd()
704 maPopupModeEndHdl.Call( this );
707 void FloatingWindow::SetTitleType( FloatWinTitleType nTitle )
709 if ( (mnTitle != nTitle) && mpWindowImpl->mpBorderWindow )
711 mnTitle = nTitle;
712 Size aOutSize = GetOutputSizePixel();
713 BorderWindowTitleType nTitleStyle;
714 if ( nTitle == FloatWinTitleType::Normal )
715 nTitleStyle = BorderWindowTitleType::Small;
716 else if ( nTitle == FloatWinTitleType::TearOff )
717 nTitleStyle = BorderWindowTitleType::Tearoff;
718 else if ( nTitle == FloatWinTitleType::Popup )
719 nTitleStyle = BorderWindowTitleType::Popup;
720 else // nTitle == FloatWinTitleType::NONE
721 nTitleStyle = BorderWindowTitleType::NONE;
722 static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->SetTitleType( nTitleStyle, aOutSize );
723 static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder );
727 void FloatingWindow::StartPopupMode( const tools::Rectangle& rRect, FloatWinPopupFlags nFlags )
729 if ( IsRollUp() )
730 RollDown();
732 // remove title
733 mnOldTitle = mnTitle;
734 if ( ( mpWindowImpl->mnStyle & WB_POPUP ) && !GetText().isEmpty() )
735 SetTitleType( FloatWinTitleType::Popup );
736 else if ( nFlags & FloatWinPopupFlags::AllowTearOff )
737 SetTitleType( FloatWinTitleType::TearOff );
738 else
739 SetTitleType( FloatWinTitleType::NONE );
741 // avoid close on focus change for decorated floating windows only
742 if( mpWindowImpl->mbFrame && (GetStyle() & WB_MOVEABLE) )
743 nFlags |= FloatWinPopupFlags::NoAppFocusClose;
745 // compute window position according to flags and arrangement
746 sal_uInt16 nArrangeIndex;
747 DoInitialLayout();
748 mpImplData->maPos = ImplCalcPos(this, rRect, nFlags, nArrangeIndex, &mpImplData->maLOKTwipsPos);
749 SetPosPixel( mpImplData->maPos );
750 ImplGetFrame()->PositionByToolkit(rRect, nFlags);
752 // set data and display window
753 // convert maFloatRect to absolute device coordinates
754 // so they can be compared across different frames
755 // !!! rRect is expected to be in screen coordinates of the parent frame window !!!
756 maFloatRect = FloatingWindow::ImplConvertToAbsPos(GetParent(), rRect);
758 maFloatRect.AdjustLeft( -2 );
759 maFloatRect.AdjustTop( -2 );
760 maFloatRect.AdjustRight(2 );
761 maFloatRect.AdjustBottom(2 );
762 mnPopupModeFlags = nFlags;
763 mbInPopupMode = true;
764 mbPopupMode = true;
765 mbPopupModeCanceled = false;
766 mbPopupModeTearOff = false;
767 mbMouseDown = false;
769 // add FloatingWindow to list of windows that are in popup mode
770 ImplSVData* pSVData = ImplGetSVData();
771 mpNextFloat = pSVData->mpWinData->mpFirstFloat;
772 pSVData->mpWinData->mpFirstFloat = this;
773 if (nFlags & FloatWinPopupFlags::GrabFocus)
775 // force key input even without focus (useful for menus)
776 mbGrabFocus = true;
777 mxPrevFocusWin = Window::SaveFocus();
778 mpWindowImpl->mpFrameData->mbHasFocus = true;
779 GrabFocus();
781 Show( true, ShowFlags::NoActivate );
784 void FloatingWindow::StartPopupMode( ToolBox* pBox, FloatWinPopupFlags nFlags )
786 mpImplData->mpBox = pBox;
788 // get selected button
789 sal_uInt16 nItemId = pBox->GetDownItemId();
791 if ( nItemId )
792 pBox->ImplFloatControl( true, this );
794 // retrieve some data from the ToolBox
795 tools::Rectangle aRect = nItemId ? pBox->GetItemRect( nItemId ) : pBox->GetOverflowRect();
797 // convert to parent's screen coordinates
798 mpImplData->maPos = GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) ) );
799 aRect.SetPos( mpImplData->maPos );
801 nFlags |=
802 FloatWinPopupFlags::AllMouseButtonClose |
803 FloatWinPopupFlags::NoMouseUpClose;
805 // set Flags for positioning
806 if ( !(nFlags & (FloatWinPopupFlags::Down | FloatWinPopupFlags::Up |
807 FloatWinPopupFlags::Left | FloatWinPopupFlags::Right)) )
809 if ( pBox->IsHorizontal() )
810 nFlags |= FloatWinPopupFlags::Down;
811 else
812 nFlags |= FloatWinPopupFlags::Right;
815 // start FloatingMode
816 StartPopupMode( aRect, nFlags );
819 void FloatingWindow::ImplEndPopupMode( FloatWinPopupEndFlags nFlags, const VclPtr<vcl::Window>& xFocusId )
821 if ( !mbInPopupMode )
822 return;
824 ImplSVData* pSVData = ImplGetSVData();
826 mbInCleanUp = true; // prevent killing this window due to focus change while working with it
828 if (!(nFlags & FloatWinPopupEndFlags::NoCloseChildren))
830 // stop the PopupMode also for all PopupMode windows created after us
831 std::vector<VclPtr<FloatingWindow>> aCancelFloats;
832 // stop the PopupMode also for all following PopupMode windows
833 for (auto pFloat = pSVData->mpWinData->mpFirstFloat;
834 pFloat != nullptr && pFloat != this;
835 pFloat = pFloat->mpNextFloat)
836 aCancelFloats.push_back(pFloat);
837 for (auto it : aCancelFloats)
838 it->EndPopupMode(FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::NoCloseChildren);
841 // delete window from the list
842 pSVData->mpWinData->mpFirstFloat = mpNextFloat;
843 mpNextFloat = nullptr;
845 FloatWinPopupFlags nPopupModeFlags = mnPopupModeFlags;
846 mbPopupModeTearOff = nFlags & FloatWinPopupEndFlags::TearOff &&
847 nPopupModeFlags & FloatWinPopupFlags::AllowTearOff;
849 // hide window again if it was not deleted
850 if (!mbPopupModeTearOff)
851 Show( false, ShowFlags::NoFocusChange );
853 if (HasChildPathFocus() && xFocusId != nullptr)
855 // restore focus to previous focus window if we still have the focus
856 Window::EndSaveFocus(xFocusId);
858 else if ( pSVData->mpWinData->mpFocusWin && pSVData->mpWinData->mpFirstFloat &&
859 ImplIsWindowOrChild( pSVData->mpWinData->mpFocusWin ) )
861 // maybe pass focus on to a suitable FloatingWindow
862 pSVData->mpWinData->mpFirstFloat->GrabFocus();
865 mbPopupModeCanceled = bool(nFlags & FloatWinPopupEndFlags::Cancel);
867 // redo title
868 SetTitleType( mnOldTitle );
870 // set ToolBox again to normal
871 if (mpImplData && mpImplData->mpBox)
873 mpImplData->mpBox->ImplFloatControl( false, this );
874 // if the parent ToolBox is in popup mode, it should be closed too.
875 if ( GetDockingManager()->IsInPopupMode( mpImplData->mpBox ) )
876 nFlags |= FloatWinPopupEndFlags::CloseAll;
878 mpImplData->mpBox = nullptr;
881 // call PopupModeEnd-Handler depending on parameter
882 if ( !(nFlags & FloatWinPopupEndFlags::DontCallHdl) )
883 ImplCallPopupModeEnd();
885 // close all other windows depending on parameter
886 if ( nFlags & FloatWinPopupEndFlags::CloseAll )
888 if ( !(nPopupModeFlags & FloatWinPopupFlags::NewLevel) )
890 if (pSVData->mpWinData->mpFirstFloat)
892 FloatingWindow* pLastLevelFloat = pSVData->mpWinData->mpFirstFloat->ImplFindLastLevelFloat();
893 pLastLevelFloat->EndPopupMode( FloatWinPopupEndFlags::Cancel | FloatWinPopupEndFlags::CloseAll );
898 mbInCleanUp = false;
901 void FloatingWindow::EndPopupMode( FloatWinPopupEndFlags nFlags )
903 ImplEndPopupMode(nFlags, mxPrevFocusWin);
906 void FloatingWindow::AddPopupModeWindow( vcl::Window* pWindow )
908 // !!! up-to-now only 1 window and not yet a list
909 mpFirstPopupModeWin = pWindow;
912 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */