/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; class SystemWindow::ImplData { public: ImplData(); std::unique_ptr mpTaskPaneList; Size maMaxOutSize; OUString maRepresentedURL; Link maCloseHdl; }; SystemWindow::ImplData::ImplData() { mpTaskPaneList = nullptr; maMaxOutSize = Size( SHRT_MAX, SHRT_MAX ); } SystemWindow::SystemWindow(WindowType nType, const char* pIdleDebugName) : Window(nType) , mbDockBtn(false) , mbHideBtn(false) , mbSysChild(false) , mbIsCalculatingInitialLayoutSize(false) , mbInitialLayoutSizeCalculated(false) , mbPaintComplete(false) , mnMenuBarMode(MenuBarMode::Normal) , mnIcon(0) , mpImplData(new ImplData) , maLayoutIdle( pIdleDebugName ) , mbIsDeferredInit(false) { mpWindowImpl->mbSysWin = true; mpWindowImpl->mnActivateMode = ActivateModeFlags::GrabFocus; //To-Do, reuse maResizeTimer maLayoutIdle.SetPriority(TaskPriority::RESIZE); maLayoutIdle.SetInvokeHandler( LINK( this, SystemWindow, ImplHandleLayoutTimerHdl ) ); } void SystemWindow::loadUI(vcl::Window* pParent, const OUString& rID, const OUString& rUIXMLDescription, const css::uno::Reference &rFrame) { mbIsDeferredInit = true; mpDialogParent = pParent; //should be unset in doDeferredInit m_pUIBuilder.reset( new VclBuilder(this, AllSettings::GetUIRootDir(), rUIXMLDescription, rID, rFrame) ); } SystemWindow::~SystemWindow() { disposeOnce(); } void SystemWindow::dispose() { maLayoutIdle.Stop(); mpImplData.reset(); // Hack to make sure code called from base ~Window does not interpret this // as a SystemWindow (which it no longer is by then): mpWindowImpl->mbSysWin = false; disposeBuilder(); mpDialogParent.clear(); mpMenuBar.clear(); Window::dispose(); } static void ImplHandleControlAccelerator( const vcl::Window* pWindow, bool bShow ) { Control *pControl = dynamic_cast(pWindow->ImplGetWindow()); if (pControl && pControl->GetText().indexOf('~') != -1) { pControl->SetShowAccelerator( bShow ); pControl->Invalidate(InvalidateFlags::Update); } } namespace { void processChildren(const vcl::Window *pParent, bool bShowAccel) { // go through its children vcl::Window* pChild = firstLogicalChildOfParent(pParent); while (pChild) { if (pChild->GetType() == WindowType::TABCONTROL) { // find currently shown tab page TabControl* pTabControl = static_cast(pChild); TabPage* pTabPage = pTabControl->GetTabPage( pTabControl->GetCurPageId() ); processChildren(pTabPage, bShowAccel); } else if (pChild->GetType() == WindowType::TABPAGE) { // bare tabpage without tabcontrol parent (options dialog) processChildren(pChild, bShowAccel); } else if ((pChild->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL) { // special controls that manage their children outside of widget layout processChildren(pChild, bShowAccel); } else { ImplHandleControlAccelerator(pChild, bShowAccel); } pChild = nextLogicalChildOfParent(pParent, pChild); } } } namespace { bool ToggleMnemonicsOnHierarchy(const CommandEvent& rCEvent, const vcl::Window *pWindow) { if (rCEvent.GetCommand() == CommandEventId::ModKeyChange && ImplGetSVData()->maNWFData.mbAutoAccel) { const CommandModKeyData *pCData = rCEvent.GetModKeyData(); const bool bShowAccel = pCData && pCData->IsMod2() && pCData->IsDown(); processChildren(pWindow, bShowAccel); return true; } return false; } } bool SystemWindow::EventNotify( NotifyEvent& rNEvt ) { if (rNEvt.GetType() == NotifyEventType::COMMAND) ToggleMnemonicsOnHierarchy(*rNEvt.GetCommandEvent(), this); // capture KeyEvents for menu handling if (rNEvt.GetType() == NotifyEventType::KEYINPUT) { MenuBar* pMBar = mpMenuBar; if ( !pMBar && ( GetType() == WindowType::FLOATINGWINDOW ) ) { vcl::Window* pWin = ImplGetFrameWindow()->ImplGetWindow(); if( pWin && pWin->IsSystemWindow() ) pMBar = static_cast(pWin)->GetMenuBar(); } if (pMBar && pMBar->ImplHandleKeyEvent(*rNEvt.GetKeyEvent())) return true; } return Window::EventNotify( rNEvt ); } bool SystemWindow::PreNotify( NotifyEvent& rNEvt ) { // capture KeyEvents for taskpane cycling if ( rNEvt.GetType() == NotifyEventType::KEYINPUT ) { if( rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_F6 && rNEvt.GetKeyEvent()->GetKeyCode().IsMod1() && !rNEvt.GetKeyEvent()->GetKeyCode().IsShift() ) { // Ctrl-F6 goes directly to the document GrabFocusToDocument(); return true; } else { TaskPaneList *pTList = mpImplData->mpTaskPaneList.get(); if( !pTList && ( GetType() == WindowType::FLOATINGWINDOW ) ) { vcl::Window* pWin = ImplGetFrameWindow()->ImplGetWindow(); if( pWin && pWin->IsSystemWindow() ) pTList = static_cast(pWin)->mpImplData->mpTaskPaneList.get(); } if( !pTList ) { // search topmost system window which is the one to handle dialog/toolbar cycling SystemWindow *pSysWin = this; vcl::Window *pWin = this; while( pWin ) { pWin = pWin->GetParent(); if( pWin && pWin->IsSystemWindow() ) pSysWin = static_cast(pWin); } pTList = pSysWin->mpImplData->mpTaskPaneList.get(); } if( pTList && pTList->HandleKeyEvent( *rNEvt.GetKeyEvent() ) ) return true; } } return Window::PreNotify( rNEvt ); } TaskPaneList* SystemWindow::GetTaskPaneList() { if( !mpImplData ) return nullptr; if( mpImplData->mpTaskPaneList ) return mpImplData->mpTaskPaneList.get(); else { mpImplData->mpTaskPaneList.reset( new TaskPaneList ); MenuBar* pMBar = mpMenuBar; if ( !pMBar && ( GetType() == WindowType::FLOATINGWINDOW ) ) { vcl::Window* pWin = ImplGetFrameWindow()->ImplGetWindow(); if ( pWin && pWin->IsSystemWindow() ) pMBar = static_cast(pWin)->GetMenuBar(); } if( pMBar ) mpImplData->mpTaskPaneList->AddWindow( pMBar->ImplGetWindow() ); return mpImplData->mpTaskPaneList.get(); } } bool SystemWindow::Close() { VclPtr xWindow = this; CallEventListeners( VclEventId::WindowClose ); if ( xWindow->isDisposed() ) return false; if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() ) return false; // Is Window not closeable, ignore close vcl::Window* pBorderWin = ImplGetBorderWindow(); WinBits nStyle; if ( pBorderWin ) nStyle = pBorderWin->GetStyle(); else nStyle = GetStyle(); if ( !(nStyle & WB_CLOSEABLE) ) return false; Hide(); return true; } void SystemWindow::TitleButtonClick( TitleButton ) { } void SystemWindow::Resizing( Size& ) { } void SystemWindow::SetRepresentedURL( const OUString& i_rURL ) { bool bChanged = (i_rURL != mpImplData->maRepresentedURL); mpImplData->maRepresentedURL = i_rURL; if ( !mbSysChild && bChanged ) { const vcl::Window* pWindow = this; while ( pWindow->mpWindowImpl->mpBorderWindow ) pWindow = pWindow->mpWindowImpl->mpBorderWindow; if ( pWindow->mpWindowImpl->mbFrame ) pWindow->mpWindowImpl->mpFrame->SetRepresentedURL( i_rURL ); } } void SystemWindow::SetIcon( sal_uInt16 nIcon ) { if ( mnIcon == nIcon ) return; mnIcon = nIcon; if ( !mbSysChild ) { const vcl::Window* pWindow = this; while ( pWindow->mpWindowImpl->mpBorderWindow ) pWindow = pWindow->mpWindowImpl->mpBorderWindow; if ( pWindow->mpWindowImpl->mbFrame ) pWindow->mpWindowImpl->mpFrame->SetIcon( nIcon ); } } void SystemWindow::ShowTitleButton( TitleButton nButton, bool bVisible ) { if ( nButton == TitleButton::Docking ) { if ( mbDockBtn != bVisible ) { mbDockBtn = bVisible; if ( mpWindowImpl->mpBorderWindow ) static_cast(mpWindowImpl->mpBorderWindow.get())->SetDockButton( bVisible ); } } else if ( nButton == TitleButton::Hide ) { if ( mbHideBtn != bVisible ) { mbHideBtn = bVisible; if ( mpWindowImpl->mpBorderWindow ) static_cast(mpWindowImpl->mpBorderWindow.get())->SetHideButton( bVisible ); } } else if ( nButton == TitleButton::Menu ) { if ( mpWindowImpl->mpBorderWindow ) static_cast(mpWindowImpl->mpBorderWindow.get())->SetMenuButton( bVisible ); } else return; } bool SystemWindow::IsTitleButtonVisible( TitleButton nButton ) const { if ( nButton == TitleButton::Docking ) return mbDockBtn; else /* if ( nButton == TitleButton::Hide ) */ return mbHideBtn; } void SystemWindow::SetMinOutputSizePixel( const Size& rSize ) { maMinOutSize = rSize; if ( mpWindowImpl->mpBorderWindow ) { static_cast(mpWindowImpl->mpBorderWindow.get())->SetMinOutputSize( rSize.Width(), rSize.Height() ); if ( mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) mpWindowImpl->mpBorderWindow->mpWindowImpl->mpFrame->SetMinClientSize( rSize.Width(), rSize.Height() ); } else if ( mpWindowImpl->mbFrame ) mpWindowImpl->mpFrame->SetMinClientSize( rSize.Width(), rSize.Height() ); } void SystemWindow::SetMaxOutputSizePixel( const Size& rSize ) { Size aSize( rSize ); if( aSize.Width() > SHRT_MAX || aSize.Width() <= 0 ) aSize.setWidth( SHRT_MAX ); if( aSize.Height() > SHRT_MAX || aSize.Height() <= 0 ) aSize.setHeight( SHRT_MAX ); mpImplData->maMaxOutSize = aSize; if ( mpWindowImpl->mpBorderWindow ) { static_cast(mpWindowImpl->mpBorderWindow.get())->SetMaxOutputSize( aSize.Width(), aSize.Height() ); if ( mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) mpWindowImpl->mpBorderWindow->mpWindowImpl->mpFrame->SetMaxClientSize( aSize.Width(), aSize.Height() ); } else if ( mpWindowImpl->mbFrame ) mpWindowImpl->mpFrame->SetMaxClientSize( aSize.Width(), aSize.Height() ); } const Size& SystemWindow::GetMaxOutputSizePixel() const { return mpImplData->maMaxOutSize; } vcl::WindowData::WindowData(std::u16string_view rStr) { vcl::WindowData& rData = *this; vcl::WindowDataMask nValidMask = vcl::WindowDataMask::NONE; sal_Int32 nIndex = 0; std::u16string_view aTokenStr = o3tl::getToken(rStr, 0, ',', nIndex); if (!aTokenStr.empty()) { rData.setX(o3tl::toInt32(aTokenStr)); if (rData.x() > -16384 && rData.x() < 16384) nValidMask |= vcl::WindowDataMask::X; else rData.setX(0); } else rData.setX(0); aTokenStr = o3tl::getToken(rStr, 0, ',', nIndex); if (!aTokenStr.empty()) { rData.setY(o3tl::toInt32(aTokenStr)); if (rData.y() > -16384 && rData.y() < 16384) nValidMask |= vcl::WindowDataMask::Y; else rData.setY(0); } else rData.setY(0); aTokenStr = o3tl::getToken(rStr, 0, ',', nIndex); if (!aTokenStr.empty()) { sal_Int32 nWidth = o3tl::toInt32(aTokenStr); if (nWidth >= 0) { rData.setWidth(nWidth); } if (rData.width() > 0 && rData.width() < 16384) nValidMask |= vcl::WindowDataMask::Width; else rData.setWidth(0); } else rData.setWidth(0); aTokenStr = o3tl::getToken(rStr, 0, ';', nIndex); if (!aTokenStr.empty()) { sal_Int32 nHeight = o3tl::toInt32(aTokenStr); if (nHeight >= 0) { rData.setHeight(nHeight); } if (rData.height() > 0 && rData.height() < 16384) nValidMask |= vcl::WindowDataMask::Height; else rData.setHeight(0); } else rData.setHeight(0); aTokenStr = o3tl::getToken(rStr, 0, ';', nIndex); if (!aTokenStr.empty()) { // #94144# allow Minimize again, should be masked out when read from configuration // 91625 - ignore Minimize vcl::WindowState nState = static_cast(o3tl::toInt32(aTokenStr)); //nState &= ~vcl::WindowState::Minimized; rData.setState(nState); nValidMask |= vcl::WindowDataMask::State; } else rData.setState(vcl::WindowState::NONE); // read maximized pos/size aTokenStr = o3tl::getToken(rStr, 0, ',', nIndex); if (!aTokenStr.empty()) { rData.SetMaximizedX(o3tl::toInt32(aTokenStr)); if (rData.GetMaximizedX() > -16384 && rData.GetMaximizedX() < 16384) nValidMask |= vcl::WindowDataMask::MaximizedX; else rData.SetMaximizedX(0); } else rData.SetMaximizedX(0); aTokenStr = o3tl::getToken(rStr, 0, ',', nIndex); if (!aTokenStr.empty()) { rData.SetMaximizedY(o3tl::toInt32(aTokenStr)); if (rData.GetMaximizedY() > -16384 && rData.GetMaximizedY() < 16384) nValidMask |= vcl::WindowDataMask::MaximizedY; else rData.SetMaximizedY(0); } else rData.SetMaximizedY(0); aTokenStr = o3tl::getToken(rStr, 0, ',', nIndex); if (!aTokenStr.empty()) { rData.SetMaximizedWidth(o3tl::toInt32(aTokenStr)); if (rData.GetMaximizedWidth() > 0 && rData.GetMaximizedWidth() < 16384) nValidMask |= vcl::WindowDataMask::MaximizedWidth; else rData.SetMaximizedWidth(0); } else rData.SetMaximizedWidth(0); aTokenStr = o3tl::getToken(rStr, 0, ';', nIndex); if (!aTokenStr.empty()) { rData.SetMaximizedHeight(o3tl::toInt32(aTokenStr)); if (rData.GetMaximizedHeight() > 0 && rData.GetMaximizedHeight() < 16384) nValidMask |= vcl::WindowDataMask::MaximizedHeight; else rData.SetMaximizedHeight(0); } else rData.SetMaximizedHeight(0); // mark valid fields rData.setMask(nValidMask); } OUString vcl::WindowData::toStr() const { const vcl::WindowDataMask nValidMask = mask(); if ( nValidMask == vcl::WindowDataMask::NONE ) return {}; OUStringBuffer rStrBuf(64); tools::Rectangle aRect = posSize(); if (nValidMask & vcl::WindowDataMask::X) rStrBuf.append(static_cast(aRect.Left())); rStrBuf.append(','); if (nValidMask & vcl::WindowDataMask::Y) rStrBuf.append(static_cast(aRect.Top())); rStrBuf.append(','); if (nValidMask & vcl::WindowDataMask::Width) rStrBuf.append(static_cast(aRect.GetWidth())); rStrBuf.append(','); if (nValidMask & vcl::WindowDataMask::Height) rStrBuf.append(static_cast(aRect.GetHeight())); rStrBuf.append( ';' ); if (nValidMask & vcl::WindowDataMask::State) { // #94144# allow Minimize again, should be masked out when read from configuration // 91625 - ignore Minimize rStrBuf.append(static_cast(state())); } rStrBuf.append(';'); if (nValidMask & vcl::WindowDataMask::MaximizedX) rStrBuf.append(static_cast(GetMaximizedX())); rStrBuf.append(','); if (nValidMask & vcl::WindowDataMask::MaximizedY) rStrBuf.append(static_cast(GetMaximizedY())); rStrBuf.append( ',' ); if (nValidMask & vcl::WindowDataMask::MaximizedWidth) rStrBuf.append(static_cast(GetMaximizedWidth())); rStrBuf.append(','); if (nValidMask & vcl::WindowDataMask::MaximizedHeight) rStrBuf.append(static_cast(GetMaximizedHeight())); rStrBuf.append(';'); return rStrBuf.makeStringAndClear(); } void SystemWindow::ImplMoveToScreen( tools::Long& io_rX, tools::Long& io_rY, tools::Long i_nWidth, tools::Long i_nHeight, vcl::Window const * i_pConfigureWin ) { AbsoluteScreenPixelRectangle aScreenRect = Application::GetScreenPosSizePixel( 0 ); for( unsigned int i = 1; i < Application::GetScreenCount(); i++ ) aScreenRect.Union( Application::GetScreenPosSizePixel( i ) ); // unfortunately most of the time width and height are not really known if( i_nWidth < 1 ) i_nWidth = 50; if( i_nHeight < 1 ) i_nHeight = 50; // check left border bool bMove = false; if( io_rX + i_nWidth < aScreenRect.Left() ) { bMove = true; io_rX = aScreenRect.Left(); } // check right border if( io_rX > aScreenRect.Right() - i_nWidth ) { bMove = true; io_rX = aScreenRect.Right() - i_nWidth; } // check top border if( io_rY + i_nHeight < aScreenRect.Top() ) { bMove = true; io_rY = aScreenRect.Top(); } // check bottom border if( io_rY > aScreenRect.Bottom() - i_nHeight ) { bMove = true; io_rY = aScreenRect.Bottom() - i_nHeight; } vcl::Window* pParent = i_pConfigureWin->GetParent(); if( bMove && pParent ) { // calculate absolute screen pos here, since that is what is contained in WindowData Point aParentAbsPos( pParent->OutputToAbsoluteScreenPixel( Point(0,0) ) ); Size aParentSizePixel( pParent->GetOutputSizePixel() ); Point aPos( (aParentSizePixel.Width() - i_nWidth) / 2, (aParentSizePixel.Height() - i_nHeight) / 2 ); io_rX = aParentAbsPos.X() + aPos.X(); io_rY = aParentAbsPos.Y() + aPos.Y(); } } void SystemWindow::SetWindowState(const vcl::WindowData& rData) { const vcl::WindowDataMask nValidMask = rData.mask(); if ( nValidMask == vcl::WindowDataMask::NONE ) return; if ( mbSysChild ) return; vcl::Window* pWindow = this; while ( pWindow->mpWindowImpl->mpBorderWindow ) pWindow = pWindow->mpWindowImpl->mpBorderWindow; if ( pWindow->mpWindowImpl->mbFrame ) { const vcl::WindowState nState = rData.state(); vcl::WindowData aState = rData; if (rData.mask() & vcl::WindowDataMask::Size) { // #i43799# adjust window state sizes if a minimal output size was set // otherwise the frame and the client might get different sizes if (maMinOutSize.Width() > static_cast(aState.width())) aState.setWidth(maMinOutSize.Width()); if (maMinOutSize.Height() > static_cast(aState.width())) aState.setHeight(maMinOutSize.Height()); } // #94144# allow Minimize again, should be masked out when read from configuration // 91625 - ignore Minimize //nState &= ~(WindowState::Minimized); aState.rState() &= vcl::WindowState::SystemMask; // normalize window positions onto screen tools::Long nX = aState.x(), nY = aState.y(); ImplMoveToScreen(nX, nY, aState.width(), aState.height(), pWindow); aState.setPos({ nX, nY }); nX = aState.GetMaximizedX(); nY = aState.GetMaximizedY(); ImplMoveToScreen(nX, nY, aState.GetMaximizedWidth(), aState.GetMaximizedHeight(), pWindow); aState.SetMaximizedX(nX); aState.SetMaximizedY(nY); // #96568# avoid having multiple frames at the same screen location // do the check only if not maximized if( !((rData.mask() & vcl::WindowDataMask::State) && (nState & vcl::WindowState::Maximized)) ) if (rData.mask() & vcl::WindowDataMask::PosSize) { AbsoluteScreenPixelRectangle aDesktop = GetDesktopRectPixel(); ImplSVData *pSVData = ImplGetSVData(); vcl::Window *pWin = pSVData->maFrameData.mpFirstFrame; bool bWrapped = false; while( pWin ) { if( !pWin->ImplIsRealParentPath( this ) && ( pWin != this ) && pWin->ImplGetWindow()->IsTopWindow() && pWin->mpWindowImpl->mbReallyVisible ) { SalFrameGeometry g = pWin->mpWindowImpl->mpFrame->GetGeometry(); if( std::abs(g.x()-aState.x()) < 2 && std::abs(g.y()-aState.y()) < 5 ) { tools::Long displacement = g.topDecoration() ? g.topDecoration() : 20; if( static_cast(aState.x() + displacement + aState.width() + g.rightDecoration()) > aDesktop.Right() || static_cast(aState.y() + displacement + aState.height() + g.bottomDecoration()) > aDesktop.Bottom() ) { // displacing would leave screen aState.setX(g.leftDecoration() ? g.leftDecoration() : 10); // should result in (0,0) aState.setY(displacement); if( bWrapped || static_cast(aState.x() + displacement + aState.width() + g.rightDecoration()) > aDesktop.Right() || static_cast(aState.y() + displacement + aState.height() + g.bottomDecoration()) > aDesktop.Bottom() ) break; // further displacement not possible -> break // avoid endless testing bWrapped = true; } else aState.move(displacement, displacement); pWin = pSVData->maFrameData.mpFirstFrame; // check new pos again } } pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame; } } mpWindowImpl->mpFrame->SetWindowState( &aState ); // do a synchronous resize for layout reasons // but use rData only when the window is not to be maximized (#i38089#) // otherwise we have no useful size information if( (rData.mask() & vcl::WindowDataMask::State) && (nState & vcl::WindowState::Maximized) ) { // query maximized size from frame SalFrameGeometry aGeometry = mpWindowImpl->mpFrame->GetGeometry(); // but use it only if it is different from the restore size (rData) // as currently only on windows the exact size of a maximized window // can be computed without actually showing the window if (aGeometry.width() != rData.width() || aGeometry.height() != rData.height()) ImplHandleResize(pWindow, aGeometry.width(), aGeometry.height()); } else if (rData.mask() & vcl::WindowDataMask::Size) ImplHandleResize(pWindow, aState.width(), aState.height()); // #i43799# use aState and not rData, see above } else { PosSizeFlags nPosSize = PosSizeFlags::NONE; if ( nValidMask & vcl::WindowDataMask::X ) nPosSize |= PosSizeFlags::X; if ( nValidMask & vcl::WindowDataMask::Y ) nPosSize |= PosSizeFlags::Y; if ( nValidMask & vcl::WindowDataMask::Width ) nPosSize |= PosSizeFlags::Width; if ( nValidMask & vcl::WindowDataMask::Height ) nPosSize |= PosSizeFlags::Height; tools::Long nX = rData.x(); tools::Long nY = rData.y(); tools::Long nWidth = rData.width(); tools::Long nHeight = rData.height(); const SalFrameGeometry& rGeom = pWindow->mpWindowImpl->mpFrame->GetGeometry(); if( nX < 0 ) nX = 0; if( nX + nWidth > static_cast(rGeom.width()) ) nX = rGeom.width() - nWidth; if( nY < 0 ) nY = 0; if( nY + nHeight > static_cast(rGeom.height()) ) nY = rGeom.height() - nHeight; setPosSizePixel( nX, nY, nWidth, nHeight, nPosSize ); } // tdf#146648 if an explicit size state was set, then use it as the preferred // size for layout if (nValidMask & vcl::WindowDataMask::Size) mbInitialLayoutSizeCalculated = true; } void SystemWindow::GetWindowState(vcl::WindowData& rData) const { vcl::WindowDataMask nValidMask = rData.mask(); if ( nValidMask == vcl::WindowDataMask::NONE ) return; if ( mbSysChild ) { rData.setMask( vcl::WindowDataMask::NONE ); return; } const vcl::Window* pWindow = this; while ( pWindow->mpWindowImpl->mpBorderWindow ) pWindow = pWindow->mpWindowImpl->mpBorderWindow; if ( pWindow->mpWindowImpl->mbFrame ) { vcl::WindowData aState; if ( mpWindowImpl->mpFrame->GetWindowState( &aState ) ) { // Limit mask only to what we've received, the rest is not set. nValidMask &= aState.mask(); rData.setMask( nValidMask ); if ( nValidMask & vcl::WindowDataMask::X ) rData.setX( aState.x() ); if ( nValidMask & vcl::WindowDataMask::Y ) rData.setY( aState.y() ); if ( nValidMask & vcl::WindowDataMask::Width ) rData.setWidth( aState.width() ); if ( nValidMask & vcl::WindowDataMask::Height ) rData.setHeight( aState.height() ); if ( nValidMask & vcl::WindowDataMask::MaximizedX ) rData.SetMaximizedX( aState.GetMaximizedX() ); if ( nValidMask & vcl::WindowDataMask::MaximizedY ) rData.SetMaximizedY( aState.GetMaximizedY() ); if ( nValidMask & vcl::WindowDataMask::MaximizedWidth ) rData.SetMaximizedWidth( aState.GetMaximizedWidth() ); if ( nValidMask & vcl::WindowDataMask::MaximizedHeight ) rData.SetMaximizedHeight( aState.GetMaximizedHeight() ); if ( nValidMask & vcl::WindowDataMask::State ) { // #94144# allow Minimize again, should be masked out when read from configuration // 91625 - ignore Minimize if (!(nValidMask & vcl::WindowDataMask::Minimized)) aState.rState() &= ~vcl::WindowState::Minimized; rData.setState(aState.state()); } rData.setMask( nValidMask ); } else rData.setMask(vcl::WindowDataMask::NONE); } else { Point aPos = GetPosPixel(); Size aSize = GetSizePixel(); vcl::WindowState nState = vcl::WindowState::NONE; nValidMask &= vcl::WindowDataMask::PosSizeState; rData.setMask( nValidMask ); if (nValidMask & vcl::WindowDataMask::X) rData.setX(aPos.X()); if (nValidMask & vcl::WindowDataMask::Y) rData.setY(aPos.Y()); if (nValidMask & vcl::WindowDataMask::Width) rData.setWidth(aSize.Width()); if (nValidMask & vcl::WindowDataMask::Height) rData.setHeight(aSize.Height()); if (nValidMask & vcl::WindowDataMask::State) rData.setState(nState); } } void SystemWindow::SetWindowState(std::u16string_view rStr) { if (rStr.empty()) return; SetWindowState(vcl::WindowData(rStr)); } OUString SystemWindow::GetWindowState(vcl::WindowDataMask nMask) const { vcl::WindowData aData; aData.setMask(nMask); GetWindowState(aData); return aData.toStr(); } void SystemWindow::SetMenuBar(MenuBar* pMenuBar) { if ( mpMenuBar == pMenuBar ) return; MenuBar* pOldMenuBar = mpMenuBar; vcl::Window* pOldWindow = nullptr; VclPtr pNewWindow; mpMenuBar = pMenuBar; if ( mpWindowImpl->mpBorderWindow && (mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW) ) { if ( pOldMenuBar ) pOldWindow = pOldMenuBar->ImplGetWindow(); else pOldWindow = nullptr; if ( pOldWindow ) { CallEventListeners( VclEventId::WindowMenubarRemoved, static_cast(pOldMenuBar) ); pOldWindow->SetAccessible( css::uno::Reference< css::accessibility::XAccessible >() ); } if ( pMenuBar ) { SAL_WARN_IF( pMenuBar->pWindow, "vcl", "SystemWindow::SetMenuBar() - MenuBars can only set in one SystemWindow at time" ); pNewWindow = MenuBar::ImplCreate(mpWindowImpl->mpBorderWindow, pOldWindow, pMenuBar); static_cast(mpWindowImpl->mpBorderWindow.get())->SetMenuBarWindow(pNewWindow); CallEventListeners( VclEventId::WindowMenubarAdded, static_cast(pMenuBar) ); } else static_cast(mpWindowImpl->mpBorderWindow.get())->SetMenuBarWindow( nullptr ); ImplToBottomChild(); if ( pOldMenuBar ) { bool bDelete = (pMenuBar == nullptr); if( bDelete && pOldWindow ) { if( mpImplData->mpTaskPaneList ) mpImplData->mpTaskPaneList->RemoveWindow( pOldWindow ); } MenuBar::ImplDestroy( pOldMenuBar, bDelete ); if( bDelete ) pOldWindow = nullptr; // will be deleted in MenuBar::ImplDestroy, } } else { if( pMenuBar ) pNewWindow = pMenuBar->ImplGetWindow(); if( pOldMenuBar ) pOldWindow = pOldMenuBar->ImplGetWindow(); } // update taskpane list to make menubar accessible if( mpImplData->mpTaskPaneList ) { if( pOldWindow ) mpImplData->mpTaskPaneList->RemoveWindow( pOldWindow ); if( pNewWindow ) mpImplData->mpTaskPaneList->AddWindow( pNewWindow ); } } void SystemWindow::SetNotebookBar(const OUString& rUIXMLDescription, const css::uno::Reference& rFrame, const NotebookBarAddonsItem& aNotebookBarAddonsItem, bool bReloadNotebookbar) { if (rUIXMLDescription != maNotebookBarUIFile || bReloadNotebookbar) { static_cast(mpWindowImpl->mpBorderWindow.get()) ->SetNotebookBar(rUIXMLDescription, rFrame, aNotebookBarAddonsItem); maNotebookBarUIFile = rUIXMLDescription; if(GetNotebookBar()) GetNotebookBar()->SetSystemWindow(this); } } void SystemWindow::CloseNotebookBar() { static_cast(mpWindowImpl->mpBorderWindow.get())->CloseNotebookBar(); maNotebookBarUIFile.clear(); } VclPtr const & SystemWindow::GetNotebookBar() const { return static_cast(mpWindowImpl->mpBorderWindow.get())->GetNotebookBar(); } void SystemWindow::SetMenuBarMode( MenuBarMode nMode ) { if ( mnMenuBarMode != nMode ) { mnMenuBarMode = nMode; if ( mpWindowImpl->mpBorderWindow && (mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW) ) { if ( nMode == MenuBarMode::Hide ) static_cast(mpWindowImpl->mpBorderWindow.get())->SetMenuBarMode( true ); else static_cast(mpWindowImpl->mpBorderWindow.get())->SetMenuBarMode( false ); } } } bool SystemWindow::ImplIsInTaskPaneList( vcl::Window* pWin ) { if( mpImplData && mpImplData->mpTaskPaneList ) return mpImplData->mpTaskPaneList->IsInList( pWin ); return false; } unsigned int SystemWindow::GetScreenNumber() const { return mpWindowImpl->mpFrame->maGeometry.screen(); } void SystemWindow::SetScreenNumber(unsigned int nDisplayScreen) { mpWindowImpl->mpFrame->SetScreenNumber( nDisplayScreen ); } void SystemWindow::SetApplicationID(const OUString &rApplicationID) { mpWindowImpl->mpFrame->SetApplicationID( rApplicationID ); } void SystemWindow::SetCloseHdl(const Link& rLink) { mpImplData->maCloseHdl = rLink; } const Link& SystemWindow::GetCloseHdl() const { return mpImplData->maCloseHdl; } void SystemWindow::queue_resize(StateChangedType /*eReason*/) { if (!isLayoutEnabled()) return; if (isCalculatingInitialLayoutSize()) return; InvalidateSizeCache(); if (hasPendingLayout()) return; maLayoutIdle.Start(); } void SystemWindow::Resize() { queue_resize(); } bool SystemWindow::isLayoutEnabled() const { //pre dtor called, and single child is a container => we're layout enabled return mpImplData && ::isLayoutEnabled(this); } Size SystemWindow::GetOptimalSize() const { if (!isLayoutEnabled()) return Window::GetOptimalSize(); Window *pBox = GetWindow(GetWindowType::FirstChild); // tdf#141318 Do the same as SystemWindow::setOptimalLayoutSize in case we're called before initial layout const_cast(this)->settingOptimalLayoutSize(pBox); Size aSize = VclContainer::getLayoutRequisition(*pBox); sal_Int32 nBorderWidth = get_border_width(); aSize.AdjustHeight(2 * nBorderWidth ); aSize.AdjustWidth(2 * nBorderWidth ); return Window::CalcWindowSize(aSize); } void SystemWindow::setPosSizeOnContainee(Size aSize, Window &rBox) { sal_Int32 nBorderWidth = get_border_width(); aSize.AdjustWidth( -(2 * nBorderWidth) ); aSize.AdjustHeight( -(2 * nBorderWidth) ); Point aPos(nBorderWidth, nBorderWidth); VclContainer::setLayoutAllocation(rBox, aPos, CalcOutputSize(aSize)); } IMPL_LINK_NOARG( SystemWindow, ImplHandleLayoutTimerHdl, Timer*, void ) { Window *pBox = GetWindow(GetWindowType::FirstChild); if (!isLayoutEnabled()) { SAL_WARN_IF(pBox, "vcl.layout", "SystemWindow has become non-layout because extra children have been added directly to it."); return; } assert(pBox); setPosSizeOnContainee(GetSizePixel(), *pBox); } void SystemWindow::SetText(const OUString& rStr) { setDeferredProperties(); Window::SetText(rStr); } OUString SystemWindow::GetText() const { const_cast(this)->setDeferredProperties(); return Window::GetText(); } void SystemWindow::settingOptimalLayoutSize(Window* /*pBox*/) { } void SystemWindow::setOptimalLayoutSize(bool bAllowWindowShrink) { maLayoutIdle.Stop(); //resize SystemWindow to fit requisition on initial show Window *pBox = GetWindow(GetWindowType::FirstChild); settingOptimalLayoutSize(pBox); Size aSize = get_preferred_size(); Size aMax(bestmaxFrameSizeForScreenSize(Size(GetDesktopRectPixel().GetSize()))); aSize.setWidth( std::min(aMax.Width(), aSize.Width()) ); aSize.setHeight( std::min(aMax.Height(), aSize.Height()) ); SetMinOutputSizePixel(aSize); if (!bAllowWindowShrink) { Size aCurrentSize = GetSizePixel(); aSize.setWidth(std::max(aSize.Width(), aCurrentSize.Width())); aSize.setHeight(std::max(aSize.Height(), aCurrentSize.Height())); } SetSizePixel(aSize); setPosSizeOnContainee(aSize, *pBox); } void SystemWindow::DoInitialLayout() { if (GetSettings().GetStyleSettings().GetAutoMnemonic()) GenerateAutoMnemonicsOnHierarchy(this); if (isLayoutEnabled()) { mbIsCalculatingInitialLayoutSize = true; setDeferredProperties(); setOptimalLayoutSize(!mbInitialLayoutSizeCalculated); mbInitialLayoutSizeCalculated = true; mbIsCalculatingInitialLayoutSize = false; } } void SystemWindow::doDeferredInit(WinBits /*nBits*/) { SAL_WARN("vcl.layout", "SystemWindow in layout without doDeferredInit impl"); } VclPtr SystemWindow::createScreenshot() { // same prerequisites as in Execute() setDeferredProperties(); ImplAdjustNWFSizes(); Show(); ToTop(); ensureRepaint(); Size aSize(GetOutputSizePixel()); VclPtr xOutput(VclPtr::Create(DeviceFormat::WITHOUT_ALPHA)); xOutput->SetOutputSizePixel(aSize); Point aPos; xOutput->DrawOutDev(aPos, aSize, aPos, aSize, *GetOutDev()); return xOutput; } void SystemWindow::PrePaint(vcl::RenderContext& rRenderContext) { Window::PrePaint(rRenderContext); mbPaintComplete = false; } void SystemWindow::PostPaint(vcl::RenderContext& rRenderContext) { Window::PostPaint(rRenderContext); mbPaintComplete = true; } void SystemWindow::ensureRepaint() { // ensure repaint Invalidate(); mbPaintComplete = false; while (!mbPaintComplete && !Application::IsQuit()) { Application::Yield(); } } void SystemWindow::CollectMenuBarMnemonics(MnemonicGenerator& rMnemonicGenerator) const { if (MenuBar* pMenu = GetMenuBar()) { sal_uInt16 nMenuItems = pMenu->GetItemCount(); for ( sal_uInt16 i = 0; i < nMenuItems; ++i ) rMnemonicGenerator.RegisterMnemonic( pMenu->GetItemText( pMenu->GetItemId( i ) ) ); } } int SystemWindow::GetMenuBarHeight() const { if (MenuBar* pMenuBar = GetMenuBar()) return pMenuBar->GetMenuBarHeight(); return 0; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */