From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- vcl/source/window/window.cxx | 3978 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3978 insertions(+) create mode 100644 vcl/source/window/window.cxx (limited to 'vcl/source/window/window.cxx') diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx new file mode 100644 index 000000000..aabd1778c --- /dev/null +++ b/vcl/source/window/window.cxx @@ -0,0 +1,3978 @@ +/* -*- 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef _WIN32 // see #140456# +#include +#endif + +#include "impldockingwrapper.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::datatransfer::dnd; + +namespace vcl { + +Window::Window( WindowType nType ) + : mpWindowImpl(new WindowImpl( *this, nType )) +{ + // true: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active + mpWindowImpl->mxOutDev->mbEnableRTL = AllSettings::GetLayoutRTL(); +} + +Window::Window( vcl::Window* pParent, WinBits nStyle ) + : mpWindowImpl(new WindowImpl( *this, WindowType::WINDOW )) +{ + // true: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active + mpWindowImpl->mxOutDev->mbEnableRTL = AllSettings::GetLayoutRTL(); + + ImplInit( pParent, nStyle, nullptr ); +} + +#if OSL_DEBUG_LEVEL > 0 +namespace +{ + OString lcl_createWindowInfo(const vcl::Window* pWindow) + { + // skip border windows, they do not carry information that + // would help with diagnosing the problem + const vcl::Window* pTempWin( pWindow ); + while ( pTempWin && pTempWin->GetType() == WindowType::BORDERWINDOW ) { + pTempWin = pTempWin->GetWindow( GetWindowType::FirstChild ); + } + // check if pTempWin is not null, otherwise use the + // original address + if ( pTempWin ) { + pWindow = pTempWin; + } + + return OString::Concat(" ") + + typeid( *pWindow ).name() + + "(" + + OUStringToOString( + pWindow->GetText(), + RTL_TEXTENCODING_UTF8 + ) + + ")"; + } +} +#endif + +void Window::dispose() +{ + assert( mpWindowImpl ); + assert( !mpWindowImpl->mbInDispose ); // should only be called from disposeOnce() + assert( (!mpWindowImpl->mpParent || + mpWindowImpl->mpParent->mpWindowImpl) && + "vcl::Window child should have its parent disposed first" ); + + // remove Key and Mouse events issued by Application::PostKey/MouseEvent + Application::RemoveMouseAndKeyEvents( this ); + + // Dispose of the canvas implementation (which, currently, has an + // own wrapper window as a child to this one. + GetOutDev()->ImplDisposeCanvas(); + + mpWindowImpl->mbInDispose = true; + + CallEventListeners( VclEventId::ObjectDying ); + + // do not send child events for frames that were registered as native frames + if( !ImplIsAccessibleNativeFrame() && mpWindowImpl->mbReallyVisible ) + if ( ImplIsAccessibleCandidate() && GetAccessibleParentWindow() ) + GetAccessibleParentWindow()->CallEventListeners( VclEventId::WindowChildDestroyed, this ); + + // remove associated data structures from dockingmanager + ImplGetDockingManager()->RemoveWindow( this ); + + // remove ownerdraw decorated windows from list in the top-most frame window + if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame ) + { + ::std::vector< VclPtr >& rList = ImplGetOwnerDrawList(); + auto p = ::std::find( rList.begin(), rList.end(), VclPtr(this) ); + if( p != rList.end() ) + rList.erase( p ); + } + + // shutdown drag and drop + Reference < XComponent > xDnDComponent( mpWindowImpl->mxDNDListenerContainer, UNO_QUERY ); + + if( xDnDComponent.is() ) + xDnDComponent->dispose(); + + if( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData ) + { + try + { + // deregister drop target listener + if( mpWindowImpl->mpFrameData->mxDropTargetListener.is() ) + { + Reference< XDragGestureRecognizer > xDragGestureRecognizer(mpWindowImpl->mpFrameData->mxDragSource, UNO_QUERY); + if( xDragGestureRecognizer.is() ) + { + xDragGestureRecognizer->removeDragGestureListener( + Reference< XDragGestureListener > (mpWindowImpl->mpFrameData->mxDropTargetListener, UNO_QUERY)); + } + + mpWindowImpl->mpFrameData->mxDropTarget->removeDropTargetListener( mpWindowImpl->mpFrameData->mxDropTargetListener ); + mpWindowImpl->mpFrameData->mxDropTargetListener.clear(); + } + + // shutdown drag and drop for this frame window + Reference< XComponent > xComponent( mpWindowImpl->mpFrameData->mxDropTarget, UNO_QUERY ); + + // DNDEventDispatcher does not hold a reference of the DropTarget, + // so it's ok if it does not support XComponent + if( xComponent.is() ) + xComponent->dispose(); + } + catch (const Exception&) + { + // can be safely ignored here. + } + } + + UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper( false ); + if ( pWrapper ) + pWrapper->WindowDestroyed( this ); + + // MT: Must be called after WindowDestroyed! + // Otherwise, if the accessible is a VCLXWindow, it will try to destroy this window again! + // But accessibility implementations from applications need this dispose. + if ( mpWindowImpl->mxAccessible.is() ) + { + Reference< XComponent> xC( mpWindowImpl->mxAccessible, UNO_QUERY ); + if ( xC.is() ) + xC->dispose(); + } + + ImplSVData* pSVData = ImplGetSVData(); + + if ( ImplGetSVHelpData().mpHelpWin && (ImplGetSVHelpData().mpHelpWin->GetParent() == this) ) + ImplDestroyHelpWindow( true ); + + SAL_WARN_IF(pSVData->mpWinData->mpTrackWin.get() == this, "vcl.window", + "Window::~Window(): Window is in TrackingMode"); + SAL_WARN_IF(IsMouseCaptured(), "vcl.window", + "Window::~Window(): Window has the mouse captured"); + + // due to old compatibility + if (pSVData->mpWinData->mpTrackWin == this) + EndTracking(); + if (IsMouseCaptured()) + ReleaseMouse(); + +#if OSL_DEBUG_LEVEL > 0 + // always perform these tests in debug builds + { + OStringBuffer aErrorStr; + bool bError = false; + vcl::Window* pTempWin; + + if ( mpWindowImpl->mpFirstChild ) + { + OStringBuffer aTempStr = "Window (" + + lcl_createWindowInfo(this) + + ") with live children destroyed: "; + pTempWin = mpWindowImpl->mpFirstChild; + while ( pTempWin ) + { + aTempStr.append(lcl_createWindowInfo(pTempWin)); + pTempWin = pTempWin->mpWindowImpl->mpNext; + } + OSL_FAIL( aTempStr.getStr() ); + Application::Abort(OStringToOUString(aTempStr, RTL_TEXTENCODING_UTF8)); + } + + if (mpWindowImpl->mpFrameData != nullptr) + { + pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap; + while ( pTempWin ) + { + if ( ImplIsRealParentPath( pTempWin ) ) + { + bError = true; + aErrorStr.append(lcl_createWindowInfo(pTempWin)); + } + pTempWin = pTempWin->mpWindowImpl->mpNextOverlap; + } + if ( bError ) + { + OString aTempStr = + "Window (" + + lcl_createWindowInfo(this) + + ") with live SystemWindows destroyed: " + + aErrorStr; + OSL_FAIL(aTempStr.getStr()); + Application::Abort(OStringToOUString(aTempStr, RTL_TEXTENCODING_UTF8)); + } + } + + bError = false; + pTempWin = pSVData->maFrameData.mpFirstFrame; + while ( pTempWin ) + { + if ( ImplIsRealParentPath( pTempWin ) ) + { + bError = true; + aErrorStr.append(lcl_createWindowInfo(pTempWin)); + } + pTempWin = pTempWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + if ( bError ) + { + OString aTempStr = "Window (" + + lcl_createWindowInfo(this) + + ") with live SystemWindows destroyed: " + + aErrorStr; + OSL_FAIL( aTempStr.getStr() ); + Application::Abort(OStringToOUString(aTempStr, RTL_TEXTENCODING_UTF8)); + } + + if ( mpWindowImpl->mpFirstOverlap ) + { + OStringBuffer aTempStr = "Window (" + + lcl_createWindowInfo(this) + + ") with live SystemWindows destroyed: "; + pTempWin = mpWindowImpl->mpFirstOverlap; + while ( pTempWin ) + { + aTempStr.append(lcl_createWindowInfo(pTempWin)); + pTempWin = pTempWin->mpWindowImpl->mpNext; + } + OSL_FAIL( aTempStr.getStr() ); + Application::Abort(OStringToOUString(aTempStr, RTL_TEXTENCODING_UTF8)); + } + + vcl::Window* pMyParent = GetParent(); + SystemWindow* pMySysWin = nullptr; + + while ( pMyParent ) + { + if ( pMyParent->IsSystemWindow() ) + { + pMySysWin = dynamic_cast(pMyParent); + } + pMyParent = pMyParent->GetParent(); + } + if ( pMySysWin && pMySysWin->ImplIsInTaskPaneList( this ) ) + { + OString aTempStr = "Window (" + + lcl_createWindowInfo(this) + + ") still in TaskPanelList!"; + OSL_FAIL( aTempStr.getStr() ); + Application::Abort(OStringToOUString(aTempStr, RTL_TEXTENCODING_UTF8)); + } + } +#endif + + if( mpWindowImpl->mbIsInTaskPaneList ) + { + vcl::Window* pMyParent = GetParent(); + SystemWindow* pMySysWin = nullptr; + + while ( pMyParent ) + { + if ( pMyParent->IsSystemWindow() ) + { + pMySysWin = dynamic_cast(pMyParent); + } + pMyParent = pMyParent->GetParent(); + } + if ( pMySysWin && pMySysWin->ImplIsInTaskPaneList( this ) ) + { + pMySysWin->GetTaskPaneList()->RemoveWindow( this ); + } + else + { + SAL_WARN( "vcl", "Window (" << GetText() << ") not found in TaskPanelList"); + } + } + + // remove from size-group if necessary + remove_from_all_size_groups(); + + // clear mnemonic labels + std::vector > aMnemonicLabels(list_mnemonic_labels()); + for (auto const& mnemonicLabel : aMnemonicLabels) + { + remove_mnemonic_label(mnemonicLabel); + } + + // hide window in order to trigger the Paint-Handling + Hide(); + + // EndExtTextInputMode + if (pSVData->mpWinData->mpExtTextInputWin == this) + { + EndExtTextInput(); + if (pSVData->mpWinData->mpExtTextInputWin == this) + pSVData->mpWinData->mpExtTextInputWin = nullptr; + } + + // check if the focus window is our child + bool bHasFocusedChild = false; + if (pSVData->mpWinData->mpFocusWin && ImplIsRealParentPath(pSVData->mpWinData->mpFocusWin)) + { + // #122232#, this must not happen and is an application bug ! but we try some cleanup to hopefully avoid crashes, see below + bHasFocusedChild = true; +#if OSL_DEBUG_LEVEL > 0 + OUString aTempStr = "Window (" + GetText() + + ") with focused child window destroyed ! THIS WILL LEAD TO CRASHES AND MUST BE FIXED !"; + SAL_WARN( "vcl", aTempStr ); + Application::Abort(aTempStr); +#endif + } + + // if we get focus pass focus to another window + vcl::Window* pOverlapWindow = ImplGetFirstOverlapWindow(); + if (pSVData->mpWinData->mpFocusWin == this + || bHasFocusedChild) // #122232#, see above, try some cleanup + { + if ( mpWindowImpl->mbFrame ) + { + pSVData->mpWinData->mpFocusWin = nullptr; + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr; + } + else + { + vcl::Window* pParent = GetParent(); + vcl::Window* pBorderWindow = mpWindowImpl->mpBorderWindow; + // when windows overlap, give focus to the parent + // of the next FrameWindow + if ( pBorderWindow ) + { + if ( pBorderWindow->ImplIsOverlapWindow() ) + pParent = pBorderWindow->mpWindowImpl->mpOverlapWindow; + } + else if ( ImplIsOverlapWindow() ) + pParent = mpWindowImpl->mpOverlapWindow; + + if ( pParent && pParent->IsEnabled() && pParent->IsInputEnabled() && ! pParent->IsInModalMode() ) + pParent->GrabFocus(); + else + mpWindowImpl->mpFrameWindow->GrabFocus(); + + // If the focus was set back to 'this' set it to nothing + if (pSVData->mpWinData->mpFocusWin == this) + { + pSVData->mpWinData->mpFocusWin = nullptr; + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr; + } + } + } + + if ( pOverlapWindow != nullptr && + pOverlapWindow->mpWindowImpl->mpLastFocusWindow == this ) + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr; + + // reset hint for DefModalDialogParent + if( pSVData->maFrameData.mpActiveApplicationFrame == this ) + pSVData->maFrameData.mpActiveApplicationFrame = nullptr; + + // reset hint of what was the last wheeled window + if (pSVData->mpWinData->mpLastWheelWindow == this) + pSVData->mpWinData->mpLastWheelWindow = nullptr; + + // reset marked windows + if ( mpWindowImpl->mpFrameData != nullptr ) + { + if ( mpWindowImpl->mpFrameData->mpFocusWin == this ) + mpWindowImpl->mpFrameData->mpFocusWin = nullptr; + if ( mpWindowImpl->mpFrameData->mpMouseMoveWin == this ) + mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr; + if ( mpWindowImpl->mpFrameData->mpMouseDownWin == this ) + mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr; + } + + // reset Deactivate-Window + if (pSVData->mpWinData->mpLastDeacWin == this) + pSVData->mpWinData->mpLastDeacWin = nullptr; + + if ( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData ) + { + if ( mpWindowImpl->mpFrameData->mnFocusId ) + Application::RemoveUserEvent( mpWindowImpl->mpFrameData->mnFocusId ); + mpWindowImpl->mpFrameData->mnFocusId = nullptr; + if ( mpWindowImpl->mpFrameData->mnMouseMoveId ) + Application::RemoveUserEvent( mpWindowImpl->mpFrameData->mnMouseMoveId ); + mpWindowImpl->mpFrameData->mnMouseMoveId = nullptr; + } + + // release SalGraphics + VclPtr pOutDev = GetOutDev(); + pOutDev->ReleaseGraphics(); + + // remove window from the lists + ImplRemoveWindow( true ); + + // de-register as "top window child" at our parent, if necessary + if ( mpWindowImpl->mbFrame ) + { + bool bIsTopWindow + = mpWindowImpl->mpWinData && (mpWindowImpl->mpWinData->mnIsTopWindow == 1); + if ( mpWindowImpl->mpRealParent && bIsTopWindow ) + { + ImplWinData* pParentWinData = mpWindowImpl->mpRealParent->ImplGetWinData(); + + auto myPos = ::std::find( pParentWinData->maTopWindowChildren.begin(), + pParentWinData->maTopWindowChildren.end(), VclPtr(this) ); + SAL_WARN_IF( myPos == pParentWinData->maTopWindowChildren.end(), "vcl.window", "Window::~Window: inconsistency in top window chain!" ); + if ( myPos != pParentWinData->maTopWindowChildren.end() ) + pParentWinData->maTopWindowChildren.erase( myPos ); + } + } + + mpWindowImpl->mpWinData.reset(); + + // remove BorderWindow or Frame window data + mpWindowImpl->mpBorderWindow.disposeAndClear(); + if ( mpWindowImpl->mbFrame ) + { + if ( pSVData->maFrameData.mpFirstFrame == this ) + pSVData->maFrameData.mpFirstFrame = mpWindowImpl->mpFrameData->mpNextFrame; + else + { + sal_Int32 nWindows = 0; + vcl::Window* pSysWin = pSVData->maFrameData.mpFirstFrame; + while ( pSysWin && pSysWin->mpWindowImpl->mpFrameData->mpNextFrame.get() != this ) + { + pSysWin = pSysWin->mpWindowImpl->mpFrameData->mpNextFrame; + nWindows++; + } + + if ( pSysWin ) + { + assert (mpWindowImpl->mpFrameData->mpNextFrame.get() != pSysWin); + pSysWin->mpWindowImpl->mpFrameData->mpNextFrame = mpWindowImpl->mpFrameData->mpNextFrame; + } + else // if it is not in the list, we can't remove it. + SAL_WARN("vcl.window", "Window " << this << " marked as frame window, " + "is missing from list of " << nWindows << " frames"); + } + if (mpWindowImpl->mpFrame) // otherwise exception during init + { + mpWindowImpl->mpFrame->SetCallback( nullptr, nullptr ); + pSVData->mpDefInst->DestroyFrame( mpWindowImpl->mpFrame ); + } + assert (mpWindowImpl->mpFrameData->mnFocusId == nullptr); + assert (mpWindowImpl->mpFrameData->mnMouseMoveId == nullptr); + + mpWindowImpl->mpFrameData->mpBuffer.disposeAndClear(); + delete mpWindowImpl->mpFrameData; + mpWindowImpl->mpFrameData = nullptr; + } + + if (mpWindowImpl->mxWindowPeer) + mpWindowImpl->mxWindowPeer->dispose(); + + // should be the last statements + mpWindowImpl.reset(); + + pOutDev.disposeAndClear(); + // just to make loplugin:vclwidgets happy + VclReferenceBase::dispose(); +} + +Window::~Window() +{ + disposeOnce(); +} + +// We will eventually being removing the inheritance of OutputDevice +// from Window. It will be replaced with a transient relationship such +// that the OutputDevice is only live for the scope of the Paint method. +// In the meantime this can help move us towards a Window use an +// OutputDevice, not being one. + +::OutputDevice const* Window::GetOutDev() const +{ + return mpWindowImpl->mxOutDev.get(); +} + +::OutputDevice* Window::GetOutDev() +{ + return mpWindowImpl->mxOutDev.get(); +} + +Color WindowOutputDevice::GetBackgroundColor() const +{ + return mxOwnerWindow->GetDisplayBackground().GetColor(); +} + +bool WindowOutputDevice::CanEnableNativeWidget() const +{ + return mxOwnerWindow->IsNativeWidgetEnabled(); +} + +} /* namespace vcl */ + +WindowImpl::WindowImpl( vcl::Window& rWindow, WindowType nType ) +{ + mxOutDev = VclPtr::Create(rWindow); + maZoom = Fraction( 1, 1 ); + mfPartialScrollX = 0.0; + mfPartialScrollY = 0.0; + maWinRegion = vcl::Region(true); + maWinClipRegion = vcl::Region(true); + mpWinData = nullptr; // Extra Window Data, that we don't need for all windows + mpFrameData = nullptr; // Frame Data + mpFrame = nullptr; // Pointer to frame window + mpSysObj = nullptr; + mpFrameWindow = nullptr; // window to top level parent (same as frame window) + mpOverlapWindow = nullptr; // first overlap parent + mpBorderWindow = nullptr; // Border-Window + mpClientWindow = nullptr; // Client-Window of a FrameWindow + mpParent = nullptr; // parent (incl. BorderWindow) + mpRealParent = nullptr; // real parent (excl. BorderWindow) + mpFirstChild = nullptr; // first child window + mpLastChild = nullptr; // last child window + mpFirstOverlap = nullptr; // first overlap window (only set in overlap windows) + mpLastOverlap = nullptr; // last overlap window (only set in overlap windows) + mpPrev = nullptr; // prev window + mpNext = nullptr; // next window + mpNextOverlap = nullptr; // next overlap window of frame + mpLastFocusWindow = nullptr; // window for focus restore + mpDlgCtrlDownWindow = nullptr; // window for dialog control + mnEventListenersIteratingCount = 0; + mnChildEventListenersIteratingCount = 0; + mpCursor = nullptr; // cursor + maPointer = PointerStyle::Arrow; + mpVCLXWindow = nullptr; + mpAccessibleInfos = nullptr; + maControlForeground = COL_TRANSPARENT; // no foreground set + maControlBackground = COL_TRANSPARENT; // no background set + mnLeftBorder = 0; // left border + mnTopBorder = 0; // top border + mnRightBorder = 0; // right border + mnBottomBorder = 0; // bottom border + mnWidthRequest = -1; // width request + mnHeightRequest = -1; // height request + mnOptimalWidthCache = -1; // optimal width cache + mnOptimalHeightCache = -1; // optimal height cache + mnX = 0; // X-Position to Parent + mnY = 0; // Y-Position to Parent + mnAbsScreenX = 0; // absolute X-position on screen, used for RTL window positioning + mpChildClipRegion = nullptr; // Child-Clip-Region when ClipChildren + mpPaintRegion = nullptr; // Paint-ClipRegion + mnStyle = 0; // style (init in ImplInitWindow) + mnPrevStyle = 0; // prevstyle (set in SetStyle) + mnExtendedStyle = WindowExtendedStyle::NONE; // extended style (init in ImplInitWindow) + mnType = nType; // type + mnGetFocusFlags = GetFocusFlags::NONE; // Flags for GetFocus()-Call + mnWaitCount = 0; // Wait-Count (>1 == "wait" mouse pointer) + mnPaintFlags = ImplPaintFlags::NONE; // Flags for ImplCallPaint + mnParentClipMode = ParentClipMode::NONE; // Flags for Parent-ClipChildren-Mode + mnActivateMode = ActivateModeFlags::NONE; // Will be converted in System/Overlap-Windows + mnDlgCtrlFlags = DialogControlFlags::NONE; // DialogControl-Flags + meAlwaysInputMode = AlwaysInputNone; // AlwaysEnableInput not called + meHalign = VclAlign::Fill; + meValign = VclAlign::Fill; + mePackType = VclPackType::Start; + mnPadding = 0; + mnGridHeight = 1; + mnGridLeftAttach = -1; + mnGridTopAttach = -1; + mnGridWidth = 1; + mnBorderWidth = 0; + mnMarginLeft = 0; + mnMarginRight = 0; + mnMarginTop = 0; + mnMarginBottom = 0; + mbFrame = false; // true: Window is a frame window + mbBorderWin = false; // true: Window is a border window + mbOverlapWin = false; // true: Window is an overlap window + mbSysWin = false; // true: SystemWindow is the base class + mbDialog = false; // true: Dialog is the base class + mbDockWin = false; // true: DockingWindow is the base class + mbFloatWin = false; // true: FloatingWindow is the base class + mbPushButton = false; // true: PushButton is the base class + mbToolBox = false; // true: ToolBox is the base class + mbMenuFloatingWindow = false; // true: MenuFloatingWindow is the base class + mbToolbarFloatingWindow = false; // true: ImplPopupFloatWin is the base class, used for subtoolbars + mbSplitter = false; // true: Splitter is the base class + mbVisible = false; // true: Show( true ) called + mbOverlapVisible = false; // true: Hide called for visible window from ImplHideAllOverlapWindow() + mbDisabled = false; // true: Enable( false ) called + mbInputDisabled = false; // true: EnableInput( false ) called + mbNoUpdate = false; // true: SetUpdateMode( false ) called + mbNoParentUpdate = false; // true: SetParentUpdateMode( false ) called + mbActive = false; // true: Window Active + mbReallyVisible = false; // true: this and all parents to an overlapped window are visible + mbReallyShown = false; // true: this and all parents to an overlapped window are shown + mbInInitShow = false; // true: we are in InitShow + mbChildPtrOverwrite = false; // true: PointerStyle overwrites Child-Pointer + mbNoPtrVisible = false; // true: ShowPointer( false ) called + mbPaintFrame = false; // true: Paint is visible, but not painted + mbInPaint = false; // true: Inside PaintHdl + mbMouseButtonDown = false; // true: BaseMouseButtonDown called + mbMouseButtonUp = false; // true: BaseMouseButtonUp called + mbKeyInput = false; // true: BaseKeyInput called + mbKeyUp = false; // true: BaseKeyUp called + mbCommand = false; // true: BaseCommand called + mbDefPos = true; // true: Position is not Set + mbDefSize = true; // true: Size is not Set + mbCallMove = true; // true: Move must be called by Show + mbCallResize = true; // true: Resize must be called by Show + mbWaitSystemResize = true; // true: Wait for System-Resize + mbInitWinClipRegion = true; // true: Calc Window Clip Region + mbInitChildRegion = false; // true: InitChildClipRegion + mbWinRegion = false; // true: Window Region + mbClipChildren = false; // true: Child-window should be clipped + mbClipSiblings = false; // true: Adjacent Child-window should be clipped + mbChildTransparent = false; // true: Child-windows are allowed to switch to transparent (incl. Parent-CLIPCHILDREN) + mbPaintTransparent = false; // true: Paints should be executed on the Parent + mbMouseTransparent = false; // true: Window is transparent for Mouse + mbDlgCtrlStart = false; // true: From here on own Dialog-Control + mbFocusVisible = false; // true: Focus Visible + mbUseNativeFocus = false; + mbNativeFocusVisible = false; // true: native Focus Visible + mbInShowFocus = false; // prevent recursion + mbInHideFocus = false; // prevent recursion + mbTrackVisible = false; // true: Tracking Visible + mbControlForeground = false; // true: Foreground-Property set + mbControlBackground = false; // true: Background-Property set + mbAlwaysOnTop = false; // true: always visible for all others windows + mbCompoundControl = false; // true: Composite Control => Listener... + mbCompoundControlHasFocus = false; // true: Composite Control has focus somewhere + mbPaintDisabled = false; // true: Paint should not be executed + mbAllResize = false; // true: Also sent ResizeEvents with 0,0 + mbInDispose = false; // true: We're still in Window::dispose() + mbExtTextInput = false; // true: ExtTextInput-Mode is active + mbInFocusHdl = false; // true: Within GetFocus-Handler + mbCreatedWithToolkit = false; + mbSuppressAccessibilityEvents = false; // true: do not send any accessibility events + mbDrawSelectionBackground = false; // true: draws transparent window background to indicate (toolbox) selection + mbIsInTaskPaneList = false; // true: window was added to the taskpanelist in the topmost system window + mnNativeBackground = ControlPart::NONE; // initialize later, depends on type + mbHelpTextDynamic = false; // true: append help id in HELP_DEBUG case + mbFakeFocusSet = false; // true: pretend as if the window has focus. + mbHexpand = false; + mbVexpand = false; + mbExpand = false; + mbFill = true; + mbSecondary = false; + mbNonHomogeneous = false; + static bool bDoubleBuffer = getenv("VCL_DOUBLEBUFFERING_FORCE_ENABLE"); + mbDoubleBufferingRequested = bDoubleBuffer; // when we are not sure, assume it cannot do double-buffering via RenderContext + mpLOKNotifier = nullptr; + mnLOKWindowId = 0; + mbLOKParentNotifier = false; + mbUseFrameData = false; +} + +WindowImpl::~WindowImpl() +{ + mpChildClipRegion.reset(); + mpAccessibleInfos.reset(); +} + +ImplWinData::ImplWinData() : + mnCursorExtWidth(0), + mbVertical(false), + mnCompositionCharRects(0), + mnTrackFlags(ShowTrackFlags::NONE), + mnIsTopWindow(sal_uInt16(~0)), // not initialized yet, 0/1 will indicate TopWindow (see IsTopWindow()) + mbMouseOver(false), + mbEnableNativeWidget(false) +{ +} + +ImplWinData::~ImplWinData() +{ + mpCompositionCharRects.reset(); +} + +ImplFrameData::ImplFrameData( vcl::Window *pWindow ) + : maPaintIdle( "vcl::Window maPaintIdle" ), + maResizeIdle( "vcl::Window maResizeIdle" ) +{ + ImplSVData* pSVData = ImplGetSVData(); + assert (pSVData->maFrameData.mpFirstFrame.get() != pWindow); + mpNextFrame = pSVData->maFrameData.mpFirstFrame; + pSVData->maFrameData.mpFirstFrame = pWindow; + mpFirstOverlap = nullptr; + mpFocusWin = nullptr; + mpMouseMoveWin = nullptr; + mpMouseDownWin = nullptr; + mpTrackWin = nullptr; + mxFontCollection = pSVData->maGDIData.mxScreenFontList; + mxFontCache = pSVData->maGDIData.mxScreenFontCache; + mnFocusId = nullptr; + mnMouseMoveId = nullptr; + mnLastMouseX = -1; + mnLastMouseY = -1; + mnBeforeLastMouseX = -1; + mnBeforeLastMouseY = -1; + mnFirstMouseX = -1; + mnFirstMouseY = -1; + mnLastMouseWinX = -1; + mnLastMouseWinY = -1; + mnModalMode = 0; + mnMouseDownTime = 0; + mnClickCount = 0; + mnFirstMouseCode = 0; + mnMouseCode = 0; + mnMouseMode = MouseEventModifiers::NONE; + mbHasFocus = false; + mbInMouseMove = false; + mbMouseIn = false; + mbStartDragCalled = false; + mbNeedSysWindow = false; + mbMinimized = false; + mbStartFocusState = false; + mbInSysObjFocusHdl = false; + mbInSysObjToTopHdl = false; + mbSysObjFocus = false; + maPaintIdle.SetPriority( TaskPriority::REPAINT ); + maPaintIdle.SetInvokeHandler( LINK( pWindow, vcl::Window, ImplHandlePaintHdl ) ); + maResizeIdle.SetPriority( TaskPriority::RESIZE ); + maResizeIdle.SetInvokeHandler( LINK( pWindow, vcl::Window, ImplHandleResizeTimerHdl ) ); + mbInternalDragGestureRecognizer = false; + mbDragging = false; + mbInBufferedPaint = false; + mnDPIX = 96; + mnDPIY = 96; + mnTouchPanPosition = -1; +} + +namespace vcl { + +bool WindowOutputDevice::AcquireGraphics() const +{ + DBG_TESTSOLARMUTEX(); + + if (isDisposed()) + return false; + + if (mpGraphics) + return true; + + mbInitLineColor = true; + mbInitFillColor = true; + mbInitFont = true; + mbInitTextColor = true; + mbInitClipRegion = true; + + ImplSVData* pSVData = ImplGetSVData(); + + mpGraphics = mxOwnerWindow->mpWindowImpl->mpFrame->AcquireGraphics(); + // try harder if no wingraphics was available directly + if ( !mpGraphics ) + { + // find another output device in the same frame + vcl::WindowOutputDevice* pReleaseOutDev = pSVData->maGDIData.mpLastWinGraphics.get(); + while ( pReleaseOutDev ) + { + if ( pReleaseOutDev->mxOwnerWindow && pReleaseOutDev->mxOwnerWindow->mpWindowImpl->mpFrame == mxOwnerWindow->mpWindowImpl->mpFrame ) + break; + pReleaseOutDev = static_cast(pReleaseOutDev->mpPrevGraphics.get()); + } + + if ( pReleaseOutDev ) + { + // steal the wingraphics from the other outdev + mpGraphics = pReleaseOutDev->mpGraphics; + pReleaseOutDev->ReleaseGraphics( false ); + } + else + { + // if needed retry after releasing least recently used wingraphics + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastWinGraphics ) + break; + pSVData->maGDIData.mpLastWinGraphics->ReleaseGraphics(); + mpGraphics = mxOwnerWindow->mpWindowImpl->mpFrame->AcquireGraphics(); + } + } + } + + if ( mpGraphics ) + { + // update global LRU list of wingraphics + mpNextGraphics = pSVData->maGDIData.mpFirstWinGraphics.get(); + pSVData->maGDIData.mpFirstWinGraphics = const_cast(this); + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = const_cast(this); + if ( !pSVData->maGDIData.mpLastWinGraphics ) + pSVData->maGDIData.mpLastWinGraphics = const_cast(this); + + mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp ); + mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable)); + } + + return mpGraphics != nullptr; +} + +void WindowOutputDevice::ReleaseGraphics( bool bRelease ) +{ + DBG_TESTSOLARMUTEX(); + + if ( !mpGraphics ) + return; + + // release the fonts of the physically released graphics device + if( bRelease ) + ImplReleaseFonts(); + + ImplSVData* pSVData = ImplGetSVData(); + + vcl::Window* pWindow = mxOwnerWindow.get(); + if (!pWindow) + return; + + if ( bRelease ) + pWindow->mpWindowImpl->mpFrame->ReleaseGraphics( mpGraphics ); + // remove from global LRU list of window graphics + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstWinGraphics = static_cast(mpNextGraphics.get()); + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastWinGraphics = static_cast(mpPrevGraphics.get()); + + mpGraphics = nullptr; + mpPrevGraphics = nullptr; + mpNextGraphics = nullptr; +} + +static sal_Int32 CountDPIScaleFactor(sal_Int32 nDPI) +{ +#ifndef MACOSX + // Setting of HiDPI is unfortunately all only a heuristic; and to add + // insult to an injury, the system is constantly lying to us about + // the DPI and whatnot + // eg. fdo#77059 - set the value from which we do consider the + // screen HiDPI to greater than 168 + if (nDPI > 216) // 96 * 2 + 96 / 4 + return 250; + else if (nDPI > 168) // 96 * 2 - 96 / 4 + return 200; + else if (nDPI > 120) // 96 * 1.5 - 96 / 4 + return 150; +#else + (void)nDPI; +#endif + + return 100; +} + +void Window::ImplInit( vcl::Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData ) +{ + SAL_WARN_IF( !mpWindowImpl->mbFrame && !pParent && GetType() != WindowType::FIXEDIMAGE, "vcl.window", + "Window::Window(): pParent == NULL" ); + + ImplSVData* pSVData = ImplGetSVData(); + vcl::Window* pRealParent = pParent; + + // inherit 3D look + if ( !mpWindowImpl->mbOverlapWin && pParent && (pParent->GetStyle() & WB_3DLOOK) ) + nStyle |= WB_3DLOOK; + + // create border window if necessary + if ( !mpWindowImpl->mbFrame && !mpWindowImpl->mbBorderWin && !mpWindowImpl->mpBorderWindow + && (nStyle & (WB_BORDER | WB_SYSTEMCHILDWINDOW) ) ) + { + BorderWindowStyle nBorderTypeStyle = BorderWindowStyle::NONE; + if( nStyle & WB_SYSTEMCHILDWINDOW ) + { + // handle WB_SYSTEMCHILDWINDOW + // these should be analogous to a top level frame; meaning they + // should have a border window with style BorderWindowStyle::Frame + // which controls their size + nBorderTypeStyle |= BorderWindowStyle::Frame; + nStyle |= WB_BORDER; + } + VclPtrInstance pBorderWin( pParent, nStyle & (WB_BORDER | WB_DIALOGCONTROL | WB_NODIALOGCONTROL), nBorderTypeStyle ); + static_cast(pBorderWin)->mpWindowImpl->mpClientWindow = this; + pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + mpWindowImpl->mpBorderWindow = pBorderWin; + pParent = mpWindowImpl->mpBorderWindow; + } + else if( !mpWindowImpl->mbFrame && ! pParent ) + { + mpWindowImpl->mbOverlapWin = true; + mpWindowImpl->mbFrame = true; + } + + // insert window in list + ImplInsertWindow( pParent ); + mpWindowImpl->mnStyle = nStyle; + + if( pParent && ! mpWindowImpl->mbFrame ) + mpWindowImpl->mxOutDev->mbEnableRTL = AllSettings::GetLayoutRTL(); + + // test for frame creation + if ( mpWindowImpl->mbFrame ) + { + // create frame + SalFrameStyleFlags nFrameStyle = SalFrameStyleFlags::NONE; + + if ( nStyle & WB_MOVEABLE ) + nFrameStyle |= SalFrameStyleFlags::MOVEABLE; + if ( nStyle & WB_SIZEABLE ) + nFrameStyle |= SalFrameStyleFlags::SIZEABLE; + if ( nStyle & WB_CLOSEABLE ) + nFrameStyle |= SalFrameStyleFlags::CLOSEABLE; + if ( nStyle & WB_APP ) + nFrameStyle |= SalFrameStyleFlags::DEFAULT; + // check for undecorated floating window + if( // 1. floating windows that are not moveable/sizeable (only closeable allowed) + ( !(nFrameStyle & ~SalFrameStyleFlags::CLOSEABLE) && + ( mpWindowImpl->mbFloatWin || ((GetType() == WindowType::BORDERWINDOW) && static_cast(this)->mbFloatWindow) || (nStyle & WB_SYSTEMFLOATWIN) ) ) || + // 2. borderwindows of floaters with ownerdraw decoration + ((GetType() == WindowType::BORDERWINDOW) && static_cast(this)->mbFloatWindow && (nStyle & WB_OWNERDRAWDECORATION) ) ) + { + nFrameStyle = SalFrameStyleFlags::FLOAT; + if( nStyle & WB_OWNERDRAWDECORATION ) + nFrameStyle |= SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::NOSHADOW; + } + else if( mpWindowImpl->mbFloatWin ) + nFrameStyle |= SalFrameStyleFlags::TOOLWINDOW; + + if( nStyle & WB_INTROWIN ) + nFrameStyle |= SalFrameStyleFlags::INTRO; + if( nStyle & WB_TOOLTIPWIN ) + nFrameStyle |= SalFrameStyleFlags::TOOLTIP; + + if( nStyle & WB_NOSHADOW ) + nFrameStyle |= SalFrameStyleFlags::NOSHADOW; + + if( nStyle & WB_SYSTEMCHILDWINDOW ) + nFrameStyle |= SalFrameStyleFlags::SYSTEMCHILD; + + switch (mpWindowImpl->mnType) + { + case WindowType::DIALOG: + case WindowType::TABDIALOG: + case WindowType::MODELESSDIALOG: + case WindowType::MESSBOX: + case WindowType::INFOBOX: + case WindowType::WARNINGBOX: + case WindowType::ERRORBOX: + case WindowType::QUERYBOX: + nFrameStyle |= SalFrameStyleFlags::DIALOG; + break; + default: + break; + } + + // tdf#144624 for the DefaultWindow, which is never visible, don't + // create an icon for it so construction of a DefaultWindow cannot + // trigger creation of a VirtualDevice which itself requires a + // DefaultWindow to exist + if( nStyle & WB_DEFAULTWIN ) + nFrameStyle |= SalFrameStyleFlags::NOICON; + + SalFrame* pParentFrame = nullptr; + if ( pParent ) + pParentFrame = pParent->mpWindowImpl->mpFrame; + SalFrame* pFrame; + if ( pSystemParentData ) + pFrame = pSVData->mpDefInst->CreateChildFrame( pSystemParentData, nFrameStyle | SalFrameStyleFlags::PLUG ); + else + pFrame = pSVData->mpDefInst->CreateFrame( pParentFrame, nFrameStyle ); + if ( !pFrame ) + { + // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario) + throw RuntimeException( + "Could not create system window!", + Reference< XInterface >() ); + } + + pFrame->SetCallback( this, ImplWindowFrameProc ); + + // set window frame data + mpWindowImpl->mpFrameData = new ImplFrameData( this ); + mpWindowImpl->mpFrame = pFrame; + mpWindowImpl->mpFrameWindow = this; + mpWindowImpl->mpOverlapWindow = this; + + if (!(nStyle & WB_DEFAULTWIN) && mpWindowImpl->mbDoubleBufferingRequested) + RequestDoubleBuffering(true); + + if ( pRealParent && IsTopWindow() ) + { + ImplWinData* pParentWinData = pRealParent->ImplGetWinData(); + pParentWinData->maTopWindowChildren.emplace_back(this ); + } + } + + // init data + mpWindowImpl->mpRealParent = pRealParent; + + // #99318: make sure fontcache and list is available before call to SetSettings + mpWindowImpl->mxOutDev->mxFontCollection = mpWindowImpl->mpFrameData->mxFontCollection; + mpWindowImpl->mxOutDev->mxFontCache = mpWindowImpl->mpFrameData->mxFontCache; + + if ( mpWindowImpl->mbFrame ) + { + if ( pParent ) + { + mpWindowImpl->mpFrameData->mnDPIX = pParent->mpWindowImpl->mpFrameData->mnDPIX; + mpWindowImpl->mpFrameData->mnDPIY = pParent->mpWindowImpl->mpFrameData->mnDPIY; + } + else + { + OutputDevice *pOutDev = GetOutDev(); + if ( pOutDev->AcquireGraphics() ) + { + mpWindowImpl->mxOutDev->mpGraphics->GetResolution( mpWindowImpl->mpFrameData->mnDPIX, mpWindowImpl->mpFrameData->mnDPIY ); + } + } + + // add ownerdraw decorated frame windows to list in the top-most frame window + // so they can be hidden on lose focus + if( nStyle & WB_OWNERDRAWDECORATION ) + ImplGetOwnerDrawList().emplace_back(this ); + + // delay settings initialization until first "real" frame + // this relies on the IntroWindow not needing any system settings + if ( !pSVData->maAppData.mbSettingsInit && + ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN)) + ) + { + // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings + ImplUpdateGlobalSettings( *pSVData->maAppData.mxSettings ); + mpWindowImpl->mxOutDev->SetSettings( *pSVData->maAppData.mxSettings ); + pSVData->maAppData.mbSettingsInit = true; + } + + // If we create a Window with default size, query this + // size directly, because we want resize all Controls to + // the correct size before we display the window + if ( nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_APP) ) + mpWindowImpl->mpFrame->GetClientSize( mpWindowImpl->mxOutDev->mnOutWidth, mpWindowImpl->mxOutDev->mnOutHeight ); + } + else + { + if ( pParent ) + { + if ( !ImplIsOverlapWindow() ) + { + mpWindowImpl->mbDisabled = pParent->mpWindowImpl->mbDisabled; + mpWindowImpl->mbInputDisabled = pParent->mpWindowImpl->mbInputDisabled; + mpWindowImpl->meAlwaysInputMode = pParent->mpWindowImpl->meAlwaysInputMode; + } + + if (!utl::ConfigManager::IsFuzzing()) + { + // we don't want to call the WindowOutputDevice override of this because + // it calls back into us. + mpWindowImpl->mxOutDev->OutputDevice::SetSettings( pParent->GetSettings() ); + } + } + + } + + // setup the scale factor for HiDPI displays + mpWindowImpl->mxOutDev->mnDPIScalePercentage = CountDPIScaleFactor(mpWindowImpl->mpFrameData->mnDPIY); + mpWindowImpl->mxOutDev->mnDPIX = mpWindowImpl->mpFrameData->mnDPIX; + mpWindowImpl->mxOutDev->mnDPIY = mpWindowImpl->mpFrameData->mnDPIY; + + if (!utl::ConfigManager::IsFuzzing()) + { + const StyleSettings& rStyleSettings = mpWindowImpl->mxOutDev->mxSettings->GetStyleSettings(); + mpWindowImpl->mxOutDev->maFont = rStyleSettings.GetAppFont(); + + if ( nStyle & WB_3DLOOK ) + { + SetTextColor( rStyleSettings.GetButtonTextColor() ); + SetBackground( Wallpaper( rStyleSettings.GetFaceColor() ) ); + } + else + { + SetTextColor( rStyleSettings.GetWindowTextColor() ); + SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) ); + } + } + else + { + mpWindowImpl->mxOutDev->maFont = OutputDevice::GetDefaultFont( DefaultFontType::FIXED, LANGUAGE_ENGLISH_US, GetDefaultFontFlags::NONE ); + } + + ImplPointToLogic(*GetOutDev(), mpWindowImpl->mxOutDev->maFont); + + (void)ImplUpdatePos(); + + // calculate app font res (except for the Intro Window or the default window) + if ( mpWindowImpl->mbFrame && !pSVData->maGDIData.mnAppFontX && ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN)) ) + ImplInitAppFontData( this ); +} + +void Window::ImplInitAppFontData( vcl::Window const * pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + tools::Long nTextHeight = pWindow->GetTextHeight(); + tools::Long nTextWidth = pWindow->approximate_char_width() * 8; + tools::Long nSymHeight = nTextHeight*4; + // Make the basis wider if the font is too narrow + // such that the dialog looks symmetrical and does not become too narrow. + // Add some extra space when the dialog has the same width, + // as a little more space is better. + if ( nSymHeight > nTextWidth ) + nTextWidth = nSymHeight; + else if ( nSymHeight+5 > nTextWidth ) + nTextWidth = nSymHeight+5; + pSVData->maGDIData.mnAppFontX = nTextWidth * 10 / 8; + pSVData->maGDIData.mnAppFontY = nTextHeight * 10; + +#ifdef MACOSX + // FIXME: this is currently only on macOS, check with other + // platforms + if( pSVData->maNWFData.mbNoFocusRects ) + { + // try to find out whether there is a large correction + // of control sizes, if yes, make app font scalings larger + // so dialog positioning is not completely off + ImplControlValue aControlValue; + tools::Rectangle aCtrlRegion( Point(), Size( nTextWidth < 10 ? 10 : nTextWidth, nTextHeight < 10 ? 10 : nTextHeight ) ); + tools::Rectangle aBoundingRgn( aCtrlRegion ); + tools::Rectangle aContentRgn( aCtrlRegion ); + if( pWindow->GetNativeControlRegion( ControlType::Editbox, ControlPart::Entire, aCtrlRegion, + ControlState::ENABLED, aControlValue, + aBoundingRgn, aContentRgn ) ) + { + // comment: the magical +6 is for the extra border in bordered + // (which is the standard) edit fields + if( aContentRgn.GetHeight() - nTextHeight > (nTextHeight+4)/4 ) + pSVData->maGDIData.mnAppFontY = (aContentRgn.GetHeight()-4) * 10; + } + } +#endif +} + +ImplWinData* Window::ImplGetWinData() const +{ + if (!mpWindowImpl->mpWinData) + { + static const char* pNoNWF = getenv( "SAL_NO_NWF" ); + + const_cast(this)->mpWindowImpl->mpWinData.reset(new ImplWinData); + mpWindowImpl->mpWinData->mbEnableNativeWidget = !(pNoNWF && *pNoNWF); // true: try to draw this control with native theme API + } + + return mpWindowImpl->mpWinData.get(); +} + + +void WindowOutputDevice::CopyDeviceArea( SalTwoRect& aPosAry, bool bWindowInvalidate ) +{ + if (aPosAry.mnSrcWidth == 0 || aPosAry.mnSrcHeight == 0 || aPosAry.mnDestWidth == 0 || aPosAry.mnDestHeight == 0) + return; + + if (bWindowInvalidate) + { + const tools::Rectangle aSrcRect(Point(aPosAry.mnSrcX, aPosAry.mnSrcY), + Size(aPosAry.mnSrcWidth, aPosAry.mnSrcHeight)); + + mxOwnerWindow->ImplMoveAllInvalidateRegions(aSrcRect, + aPosAry.mnDestX-aPosAry.mnSrcX, + aPosAry.mnDestY-aPosAry.mnSrcY, + false); + + mpGraphics->CopyArea(aPosAry.mnDestX, aPosAry.mnDestY, + aPosAry.mnSrcX, aPosAry.mnSrcY, + aPosAry.mnSrcWidth, aPosAry.mnSrcHeight, + *this); + + return; + } + + OutputDevice::CopyDeviceArea(aPosAry, bWindowInvalidate); +} + +const OutputDevice* WindowOutputDevice::DrawOutDevDirectCheck(const OutputDevice& rSrcDev) const +{ + const OutputDevice* pSrcDevChecked; + if ( this == &rSrcDev ) + pSrcDevChecked = nullptr; + else if (GetOutDevType() != rSrcDev.GetOutDevType()) + pSrcDevChecked = &rSrcDev; + else if (mxOwnerWindow->mpWindowImpl->mpFrameWindow == static_cast(rSrcDev).mxOwnerWindow->mpWindowImpl->mpFrameWindow) + pSrcDevChecked = nullptr; + else + pSrcDevChecked = &rSrcDev; + + return pSrcDevChecked; +} + +void WindowOutputDevice::DrawOutDevDirectProcess( const OutputDevice& rSrcDev, SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) +{ + if (pSrcGraphics) + mpGraphics->CopyBits(rPosAry, *pSrcGraphics, *this, rSrcDev); + else + mpGraphics->CopyBits(rPosAry, *this); +} + +SalGraphics* Window::ImplGetFrameGraphics() const +{ + if ( mpWindowImpl->mpFrameWindow->GetOutDev()->mpGraphics ) + { + mpWindowImpl->mpFrameWindow->GetOutDev()->mbInitClipRegion = true; + } + else + { + OutputDevice* pFrameWinOutDev = mpWindowImpl->mpFrameWindow->GetOutDev(); + if ( ! pFrameWinOutDev->AcquireGraphics() ) + { + return nullptr; + } + } + mpWindowImpl->mpFrameWindow->GetOutDev()->mpGraphics->ResetClipRegion(); + return mpWindowImpl->mpFrameWindow->GetOutDev()->mpGraphics; +} + +void Window::ImplSetReallyVisible() +{ + // #i43594# it is possible that INITSHOW was never send, because the visibility state changed between + // ImplCallInitShow() and ImplSetReallyVisible() when called from Show() + // mbReallyShown is a useful indicator + if( !mpWindowImpl->mbReallyShown ) + ImplCallInitShow(); + + bool bBecameReallyVisible = !mpWindowImpl->mbReallyVisible; + + GetOutDev()->mbDevOutput = true; + mpWindowImpl->mbReallyVisible = true; + mpWindowImpl->mbReallyShown = true; + + // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge. + // For this, the data member of the event must not be NULL. + // Previously, we did this in Window::Show, but there some events got lost in certain situations. Now + // we're doing it when the visibility really changes + if( bBecameReallyVisible && ImplIsAccessibleCandidate() ) + CallEventListeners( VclEventId::WindowShow, this ); + // TODO. It's kind of a hack that we're re-using the VclEventId::WindowShow. Normally, we should + // introduce another event which explicitly triggers the Accessibility implementations. + + vcl::Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbVisible ) + pWindow->ImplSetReallyVisible(); + pWindow = pWindow->mpWindowImpl->mpNext; + } + + pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbVisible ) + pWindow->ImplSetReallyVisible(); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +void Window::ImplInitResolutionSettings() +{ + // recalculate AppFont-resolution and DPI-resolution + if (mpWindowImpl->mbFrame) + { + GetOutDev()->mnDPIX = mpWindowImpl->mpFrameData->mnDPIX; + GetOutDev()->mnDPIY = mpWindowImpl->mpFrameData->mnDPIY; + + // setup the scale factor for HiDPI displays + GetOutDev()->mnDPIScalePercentage = CountDPIScaleFactor(mpWindowImpl->mpFrameData->mnDPIY); + const StyleSettings& rStyleSettings = GetOutDev()->mxSettings->GetStyleSettings(); + SetPointFont(*GetOutDev(), rStyleSettings.GetAppFont()); + } + else if ( mpWindowImpl->mpParent ) + { + GetOutDev()->mnDPIX = mpWindowImpl->mpParent->GetOutDev()->mnDPIX; + GetOutDev()->mnDPIY = mpWindowImpl->mpParent->GetOutDev()->mnDPIY; + GetOutDev()->mnDPIScalePercentage = mpWindowImpl->mpParent->GetOutDev()->mnDPIScalePercentage; + } + + // update the recalculated values for logical units + // and also tools belonging to the values + if (IsMapModeEnabled()) + { + MapMode aMapMode = GetMapMode(); + SetMapMode(); + SetMapMode( aMapMode ); + } +} + +void Window::ImplPointToLogic(vcl::RenderContext const & rRenderContext, vcl::Font& rFont) const +{ + Size aSize = rFont.GetFontSize(); + + if (aSize.Width()) + { + aSize.setWidth( aSize.Width() * ( mpWindowImpl->mpFrameData->mnDPIX) ); + aSize.AdjustWidth(72 / 2 ); + aSize.setWidth( aSize.Width() / 72 ); + } + aSize.setHeight( aSize.Height() * ( mpWindowImpl->mpFrameData->mnDPIY) ); + aSize.AdjustHeight(72/2 ); + aSize.setHeight( aSize.Height() / 72 ); + + if (rRenderContext.IsMapModeEnabled()) + aSize = rRenderContext.PixelToLogic(aSize); + + rFont.SetFontSize(aSize); +} + +void Window::ImplLogicToPoint(vcl::RenderContext const & rRenderContext, vcl::Font& rFont) const +{ + Size aSize = rFont.GetFontSize(); + + if (rRenderContext.IsMapModeEnabled()) + aSize = rRenderContext.LogicToPixel(aSize); + + if (aSize.Width()) + { + aSize.setWidth( aSize.Width() * 72 ); + aSize.AdjustWidth(mpWindowImpl->mpFrameData->mnDPIX / 2 ); + aSize.setWidth( aSize.Width() / ( mpWindowImpl->mpFrameData->mnDPIX) ); + } + aSize.setHeight( aSize.Height() * 72 ); + aSize.AdjustHeight(mpWindowImpl->mpFrameData->mnDPIY / 2 ); + aSize.setHeight( aSize.Height() / ( mpWindowImpl->mpFrameData->mnDPIY) ); + + rFont.SetFontSize(aSize); +} + +bool Window::ImplUpdatePos() +{ + bool bSysChild = false; + + if ( ImplIsOverlapWindow() ) + { + GetOutDev()->mnOutOffX = mpWindowImpl->mnX; + GetOutDev()->mnOutOffY = mpWindowImpl->mnY; + } + else + { + vcl::Window* pParent = ImplGetParent(); + + GetOutDev()->mnOutOffX = mpWindowImpl->mnX + pParent->GetOutDev()->mnOutOffX; + GetOutDev()->mnOutOffY = mpWindowImpl->mnY + pParent->GetOutDev()->mnOutOffY; + } + + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + if ( pChild->ImplUpdatePos() ) + bSysChild = true; + pChild = pChild->mpWindowImpl->mpNext; + } + + if ( mpWindowImpl->mpSysObj ) + bSysChild = true; + + return bSysChild; +} + +void Window::ImplUpdateSysObjPos() +{ + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->SetPosSize( GetOutDev()->mnOutOffX, GetOutDev()->mnOutOffY, GetOutDev()->mnOutWidth, GetOutDev()->mnOutHeight ); + + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplUpdateSysObjPos(); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +void Window::ImplPosSizeWindow( tools::Long nX, tools::Long nY, + tools::Long nWidth, tools::Long nHeight, PosSizeFlags nFlags ) +{ + bool bNewPos = false; + bool bNewSize = false; + bool bCopyBits = false; + tools::Long nOldOutOffX = GetOutDev()->mnOutOffX; + tools::Long nOldOutOffY = GetOutDev()->mnOutOffY; + tools::Long nOldOutWidth = GetOutDev()->mnOutWidth; + tools::Long nOldOutHeight = GetOutDev()->mnOutHeight; + std::unique_ptr pOverlapRegion; + std::unique_ptr pOldRegion; + + if ( IsReallyVisible() ) + { + tools::Rectangle aOldWinRect( Point( nOldOutOffX, nOldOutOffY ), + Size( nOldOutWidth, nOldOutHeight ) ); + pOldRegion.reset( new vcl::Region( aOldWinRect ) ); + if ( mpWindowImpl->mbWinRegion ) + pOldRegion->Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + + if ( GetOutDev()->mnOutWidth && GetOutDev()->mnOutHeight && !mpWindowImpl->mbPaintTransparent && + !mpWindowImpl->mbInitWinClipRegion && !mpWindowImpl->maWinClipRegion.IsEmpty() && + !HasPaintEvent() ) + bCopyBits = true; + } + + bool bnXRecycled = false; // avoid duplicate mirroring in RTL case + if ( nFlags & PosSizeFlags::Width ) + { + if(!( nFlags & PosSizeFlags::X )) + { + nX = mpWindowImpl->mnX; + nFlags |= PosSizeFlags::X; + bnXRecycled = true; // we're using a mnX which was already mirrored in RTL case + } + + if ( nWidth < 0 ) + nWidth = 0; + if ( nWidth != GetOutDev()->mnOutWidth ) + { + GetOutDev()->mnOutWidth = nWidth; + bNewSize = true; + bCopyBits = false; + } + } + if ( nFlags & PosSizeFlags::Height ) + { + if ( nHeight < 0 ) + nHeight = 0; + if ( nHeight != GetOutDev()->mnOutHeight ) + { + GetOutDev()->mnOutHeight = nHeight; + bNewSize = true; + bCopyBits = false; + } + } + + if ( nFlags & PosSizeFlags::X ) + { + tools::Long nOrgX = nX; + Point aPtDev( Point( nX+GetOutDev()->mnOutOffX, 0 ) ); + OutputDevice *pOutDev = GetOutDev(); + if( pOutDev->HasMirroredGraphics() ) + { + aPtDev.setX( GetOutDev()->mpGraphics->mirror2( aPtDev.X(), *GetOutDev() ) ); + + // #106948# always mirror our pos if our parent is not mirroring, even + // if we are also not mirroring + // RTL: check if parent is in different coordinates + if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->GetOutDev()->ImplIsAntiparallel() ) + { + nX = mpWindowImpl->mpParent->GetOutDev()->mnOutWidth - GetOutDev()->mnOutWidth - nX; + } + /* #i99166# An LTR window in RTL UI that gets sized only would be + expected to not moved its upper left point + */ + if( bnXRecycled ) + { + if( GetOutDev()->ImplIsAntiparallel() ) + { + aPtDev.setX( mpWindowImpl->mnAbsScreenX ); + nOrgX = mpWindowImpl->maPos.X(); + } + } + } + else if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->GetOutDev()->ImplIsAntiparallel() ) + { + // mirrored window in LTR UI + nX = mpWindowImpl->mpParent->GetOutDev()->mnOutWidth - GetOutDev()->mnOutWidth - nX; + } + + // check maPos as well, as it could have been changed for client windows (ImplCallMove()) + if ( mpWindowImpl->mnAbsScreenX != aPtDev.X() || nX != mpWindowImpl->mnX || nOrgX != mpWindowImpl->maPos.X() ) + { + if ( bCopyBits && !pOverlapRegion ) + { + pOverlapRegion.reset( new vcl::Region() ); + ImplCalcOverlapRegion( GetOutputRectPixel(), + *pOverlapRegion, false, true ); + } + mpWindowImpl->mnX = nX; + mpWindowImpl->maPos.setX( nOrgX ); + mpWindowImpl->mnAbsScreenX = aPtDev.X(); + bNewPos = true; + } + } + if ( nFlags & PosSizeFlags::Y ) + { + // check maPos as well, as it could have been changed for client windows (ImplCallMove()) + if ( nY != mpWindowImpl->mnY || nY != mpWindowImpl->maPos.Y() ) + { + if ( bCopyBits && !pOverlapRegion ) + { + pOverlapRegion.reset( new vcl::Region() ); + ImplCalcOverlapRegion( GetOutputRectPixel(), + *pOverlapRegion, false, true ); + } + mpWindowImpl->mnY = nY; + mpWindowImpl->maPos.setY( nY ); + bNewPos = true; + } + } + + if ( !(bNewPos || bNewSize) ) + return; + + bool bUpdateSysObjPos = false; + if ( bNewPos ) + bUpdateSysObjPos = ImplUpdatePos(); + + // the borderwindow always specifies the position for its client window + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->maPos = mpWindowImpl->mpBorderWindow->mpWindowImpl->maPos; + + if ( mpWindowImpl->mpClientWindow ) + { + mpWindowImpl->mpClientWindow->ImplPosSizeWindow( mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder, + mpWindowImpl->mpClientWindow->mpWindowImpl->mnTopBorder, + GetOutDev()->mnOutWidth - mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnRightBorder, + GetOutDev()->mnOutHeight - mpWindowImpl->mpClientWindow->mpWindowImpl->mnTopBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnBottomBorder, + PosSizeFlags::X | PosSizeFlags::Y | + PosSizeFlags::Width | PosSizeFlags::Height ); + // If we have a client window, then this is the position + // of the Application's floating windows + mpWindowImpl->mpClientWindow->mpWindowImpl->maPos = mpWindowImpl->maPos; + if ( bNewPos ) + { + if ( mpWindowImpl->mpClientWindow->IsVisible() ) + { + mpWindowImpl->mpClientWindow->ImplCallMove(); + } + else + { + mpWindowImpl->mpClientWindow->mpWindowImpl->mbCallMove = true; + } + } + } + + // Move()/Resize() will be called only for Show(), such that + // at least one is called before Show() + if ( IsVisible() ) + { + if ( bNewPos ) + { + ImplCallMove(); + } + if ( bNewSize ) + { + ImplCallResize(); + } + } + else + { + if ( bNewPos ) + mpWindowImpl->mbCallMove = true; + if ( bNewSize ) + mpWindowImpl->mbCallResize = true; + } + + bool bUpdateSysObjClip = false; + if ( IsReallyVisible() ) + { + if ( bNewPos || bNewSize ) + { + // set Clip-Flag + bUpdateSysObjClip = !ImplSetClipFlag( true ); + } + + // invalidate window content ? + if ( bNewPos || (GetOutDev()->mnOutWidth > nOldOutWidth) || (GetOutDev()->mnOutHeight > nOldOutHeight) ) + { + if ( bNewPos ) + { + bool bInvalidate = false; + bool bParentPaint = true; + if ( !ImplIsOverlapWindow() ) + bParentPaint = mpWindowImpl->mpParent->IsPaintEnabled(); + if ( bCopyBits && bParentPaint && !HasPaintEvent() ) + { + vcl::Region aRegion( GetOutputRectPixel() ); + if ( mpWindowImpl->mbWinRegion ) + aRegion.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + ImplClipBoundaries( aRegion, false, true ); + if ( !pOverlapRegion->IsEmpty() ) + { + pOverlapRegion->Move( GetOutDev()->mnOutOffX - nOldOutOffX, GetOutDev()->mnOutOffY - nOldOutOffY ); + aRegion.Exclude( *pOverlapRegion ); + } + if ( !aRegion.IsEmpty() ) + { + // adapt Paint areas + ImplMoveAllInvalidateRegions( tools::Rectangle( Point( nOldOutOffX, nOldOutOffY ), + Size( nOldOutWidth, nOldOutHeight ) ), + GetOutDev()->mnOutOffX - nOldOutOffX, GetOutDev()->mnOutOffY - nOldOutOffY, + true ); + SalGraphics* pGraphics = ImplGetFrameGraphics(); + if ( pGraphics ) + { + + OutputDevice *pOutDev = GetOutDev(); + const bool bSelectClipRegion = pOutDev->SelectClipRegion( aRegion, pGraphics ); + if ( bSelectClipRegion ) + { + pGraphics->CopyArea( GetOutDev()->mnOutOffX, GetOutDev()->mnOutOffY, + nOldOutOffX, nOldOutOffY, + nOldOutWidth, nOldOutHeight, + *GetOutDev() ); + } + else + bInvalidate = true; + } + else + bInvalidate = true; + if ( !bInvalidate ) + { + if ( !pOverlapRegion->IsEmpty() ) + ImplInvalidateFrameRegion( pOverlapRegion.get(), InvalidateFlags::Children ); + } + } + else + bInvalidate = true; + } + else + bInvalidate = true; + if ( bInvalidate ) + ImplInvalidateFrameRegion( nullptr, InvalidateFlags::Children ); + } + else + { + vcl::Region aRegion( GetOutputRectPixel() ); + aRegion.Exclude( *pOldRegion ); + if ( mpWindowImpl->mbWinRegion ) + aRegion.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + ImplClipBoundaries( aRegion, false, true ); + if ( !aRegion.IsEmpty() ) + ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children ); + } + } + + // invalidate Parent or Overlaps + if ( bNewPos || + (GetOutDev()->mnOutWidth < nOldOutWidth) || (GetOutDev()->mnOutHeight < nOldOutHeight) ) + { + vcl::Region aRegion( *pOldRegion ); + if ( !mpWindowImpl->mbPaintTransparent ) + ImplExcludeWindowRegion( aRegion ); + ImplClipBoundaries( aRegion, false, true ); + if ( !aRegion.IsEmpty() && !mpWindowImpl->mpBorderWindow ) + ImplInvalidateParentFrameRegion( aRegion ); + } + } + + // adapt system objects + if ( bUpdateSysObjClip ) + ImplUpdateSysObjClip(); + if ( bUpdateSysObjPos ) + ImplUpdateSysObjPos(); + if ( bNewSize && mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->SetPosSize( GetOutDev()->mnOutOffX, GetOutDev()->mnOutOffY, GetOutDev()->mnOutWidth, GetOutDev()->mnOutHeight ); +} + +void Window::ImplNewInputContext() +{ + ImplSVData* pSVData = ImplGetSVData(); + vcl::Window* pFocusWin = pSVData->mpWinData->mpFocusWin; + if ( !pFocusWin || !pFocusWin->mpWindowImpl || pFocusWin->isDisposed() ) + return; + + // Is InputContext changed? + const InputContext& rInputContext = pFocusWin->GetInputContext(); + if ( rInputContext == pFocusWin->mpWindowImpl->mpFrameData->maOldInputContext ) + return; + + pFocusWin->mpWindowImpl->mpFrameData->maOldInputContext = rInputContext; + + SalInputContext aNewContext; + const vcl::Font& rFont = rInputContext.GetFont(); + const OUString& rFontName = rFont.GetFamilyName(); + rtl::Reference pFontInstance; + aNewContext.mpFont = nullptr; + if (!rFontName.isEmpty()) + { + OutputDevice *pFocusWinOutDev = pFocusWin->GetOutDev(); + Size aSize = pFocusWinOutDev->ImplLogicToDevicePixel( rFont.GetFontSize() ); + if ( !aSize.Height() ) + { + // only set default sizes if the font height in logical + // coordinates equals 0 + if ( rFont.GetFontSize().Height() ) + aSize.setHeight( 1 ); + else + aSize.setHeight( (12*pFocusWin->GetOutDev()->mnDPIY)/72 ); + } + pFontInstance = pFocusWin->GetOutDev()->mxFontCache->GetFontInstance( + pFocusWin->GetOutDev()->mxFontCollection.get(), + rFont, aSize, static_cast(aSize.Height()) ); + if ( pFontInstance ) + aNewContext.mpFont = pFontInstance; + } + aNewContext.mnOptions = rInputContext.GetOptions(); + pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext ); +} + +void Window::SetDumpAsPropertyTreeHdl(const Link& rLink) +{ + if (mpWindowImpl) // may be called after dispose + { + mpWindowImpl->maDumpAsPropertyTreeHdl = rLink; + } +} + +void Window::SetModalHierarchyHdl(const Link& rLink) +{ + ImplGetFrame()->SetModalHierarchyHdl(rLink); +} + +KeyIndicatorState Window::GetIndicatorState() const +{ + return mpWindowImpl->mpFrame->GetIndicatorState(); +} + +void Window::SimulateKeyPress( sal_uInt16 nKeyCode ) const +{ + mpWindowImpl->mpFrame->SimulateKeyPress(nKeyCode); +} + +void Window::KeyInput( const KeyEvent& rKEvt ) +{ + KeyCode cod = rKEvt.GetKeyCode (); + bool autoacc = ImplGetSVData()->maNWFData.mbAutoAccel; + + // do not respond to accelerators unless Alt or Ctrl is held + if (cod.GetCode () >= 0x200 && cod.GetCode () <= 0x219) + { + if (autoacc && cod.GetModifier () != KEY_MOD2 && !(cod.GetModifier() & KEY_MOD1)) + return; + } + + NotifyEvent aNEvt( MouseNotifyEvent::KEYINPUT, this, &rKEvt ); + if ( !CompatNotify( aNEvt ) ) + mpWindowImpl->mbKeyInput = true; +} + +void Window::KeyUp( const KeyEvent& rKEvt ) +{ + NotifyEvent aNEvt( MouseNotifyEvent::KEYUP, this, &rKEvt ); + if ( !CompatNotify( aNEvt ) ) + mpWindowImpl->mbKeyUp = true; +} + +void Window::Draw( OutputDevice*, const Point&, SystemTextColorFlags ) +{ +} + +void Window::Move() {} + +void Window::Resize() {} + +void Window::Activate() {} + +void Window::Deactivate() {} + +void Window::GetFocus() +{ + if ( HasFocus() && mpWindowImpl->mpLastFocusWindow && !(mpWindowImpl->mnDlgCtrlFlags & DialogControlFlags::WantFocus) ) + { + VclPtr xWindow(this); + mpWindowImpl->mpLastFocusWindow->GrabFocus(); + if( xWindow->isDisposed() ) + return; + } + + NotifyEvent aNEvt( MouseNotifyEvent::GETFOCUS, this ); + CompatNotify( aNEvt ); +} + +void Window::LoseFocus() +{ + NotifyEvent aNEvt( MouseNotifyEvent::LOSEFOCUS, this ); + CompatNotify( aNEvt ); +} + +void Window::SetHelpHdl(const Link& rLink) +{ + if (mpWindowImpl) // may be called after dispose + { + mpWindowImpl->maHelpRequestHdl = rLink; + } +} + +void Window::RequestHelp( const HelpEvent& rHEvt ) +{ + // if Balloon-Help is requested, show the balloon + // with help text set + if ( rHEvt.GetMode() & HelpEventMode::BALLOON ) + { + OUString rStr = GetHelpText(); + if ( rStr.isEmpty() ) + rStr = GetQuickHelpText(); + if ( rStr.isEmpty() && ImplGetParent() && !ImplIsOverlapWindow() ) + ImplGetParent()->RequestHelp( rHEvt ); + else + { + Point aPos = GetPosPixel(); + if ( ImplGetParent() && !ImplIsOverlapWindow() ) + aPos = OutputToScreenPixel(Point(0, 0)); + tools::Rectangle aRect( aPos, GetSizePixel() ); + + Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), aRect, rStr ); + } + } + else if ( rHEvt.GetMode() & HelpEventMode::QUICK ) + { + const OUString& rStr = GetQuickHelpText(); + if ( rStr.isEmpty() && ImplGetParent() && !ImplIsOverlapWindow() ) + ImplGetParent()->RequestHelp( rHEvt ); + else + { + Point aPos = GetPosPixel(); + if ( ImplGetParent() && !ImplIsOverlapWindow() ) + aPos = OutputToScreenPixel(Point(0, 0)); + tools::Rectangle aRect( aPos, GetSizePixel() ); + Help::ShowQuickHelp( this, aRect, rStr, QuickHelpFlags::CtrlText ); + } + } + else if (!mpWindowImpl->maHelpRequestHdl.IsSet() || mpWindowImpl->maHelpRequestHdl.Call(*this)) + { + OUString aStrHelpId( OStringToOUString( GetHelpId(), RTL_TEXTENCODING_UTF8 ) ); + if ( aStrHelpId.isEmpty() && ImplGetParent() ) + ImplGetParent()->RequestHelp( rHEvt ); + else + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if( !aStrHelpId.isEmpty() ) + pHelp->Start( aStrHelpId, this ); + else + pHelp->Start( OOO_HELP_INDEX, this ); + } + } + } +} + +void Window::Command( const CommandEvent& rCEvt ) +{ + CallEventListeners( VclEventId::WindowCommand, const_cast(&rCEvt) ); + + NotifyEvent aNEvt( MouseNotifyEvent::COMMAND, this, &rCEvt ); + if ( !CompatNotify( aNEvt ) ) + mpWindowImpl->mbCommand = true; +} + +void Window::Tracking( const TrackingEvent& rTEvt ) +{ + + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + pWrapper->Tracking( rTEvt ); +} + +void Window::StateChanged(StateChangedType eType) +{ + switch (eType) + { + //stuff that doesn't invalidate the layout + case StateChangedType::ControlForeground: + case StateChangedType::ControlBackground: + case StateChangedType::UpdateMode: + case StateChangedType::ReadOnly: + case StateChangedType::Enable: + case StateChangedType::State: + case StateChangedType::Data: + case StateChangedType::InitShow: + case StateChangedType::ControlFocus: + break; + //stuff that does invalidate the layout + default: + queue_resize(eType); + break; + } +} + +void Window::SetStyle( WinBits nStyle ) +{ + if ( mpWindowImpl && mpWindowImpl->mnStyle != nStyle ) + { + mpWindowImpl->mnPrevStyle = mpWindowImpl->mnStyle; + mpWindowImpl->mnStyle = nStyle; + CompatStateChanged( StateChangedType::Style ); + } +} + +void Window::SetExtendedStyle( WindowExtendedStyle nExtendedStyle ) +{ + + if ( mpWindowImpl->mnExtendedStyle == nExtendedStyle ) + return; + + vcl::Window* pWindow = ImplGetBorderWindow(); + if( ! pWindow ) + pWindow = this; + if( pWindow->mpWindowImpl->mbFrame ) + { + SalExtStyle nExt = 0; + if( nExtendedStyle & WindowExtendedStyle::Document ) + nExt |= SAL_FRAME_EXT_STYLE_DOCUMENT; + if( nExtendedStyle & WindowExtendedStyle::DocModified ) + nExt |= SAL_FRAME_EXT_STYLE_DOCMODIFIED; + + pWindow->ImplGetFrame()->SetExtendedFrameStyle( nExt ); + } + mpWindowImpl->mnExtendedStyle = nExtendedStyle; +} + +void Window::SetBorderStyle( WindowBorderStyle nBorderStyle ) +{ + + if ( !mpWindowImpl->mpBorderWindow ) + return; + + if( nBorderStyle == WindowBorderStyle::REMOVEBORDER && + ! mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame && + mpWindowImpl->mpBorderWindow->mpWindowImpl->mpParent + ) + { + // this is a little awkward: some controls (e.g. svtools ProgressBar) + // cannot avoid getting constructed with WB_BORDER but want to disable + // borders in case of NWF drawing. So they need a method to remove their border window + VclPtr pBorderWin = mpWindowImpl->mpBorderWindow; + // remove us as border window's client + pBorderWin->mpWindowImpl->mpClientWindow = nullptr; + mpWindowImpl->mpBorderWindow = nullptr; + mpWindowImpl->mpRealParent = pBorderWin->mpWindowImpl->mpParent; + // reparent us above the border window + SetParent( pBorderWin->mpWindowImpl->mpParent ); + // set us to the position and size of our previous border + Point aBorderPos( pBorderWin->GetPosPixel() ); + Size aBorderSize( pBorderWin->GetSizePixel() ); + setPosSizePixel( aBorderPos.X(), aBorderPos.Y(), aBorderSize.Width(), aBorderSize.Height() ); + // release border window + pBorderWin.disposeAndClear(); + + // set new style bits + SetStyle( GetStyle() & (~WB_BORDER) ); + } + else + { + if ( mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW ) + static_cast(mpWindowImpl->mpBorderWindow.get())->SetBorderStyle( nBorderStyle ); + else + mpWindowImpl->mpBorderWindow->SetBorderStyle( nBorderStyle ); + } +} + +WindowBorderStyle Window::GetBorderStyle() const +{ + + if ( mpWindowImpl->mpBorderWindow ) + { + if ( mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW ) + return static_cast(mpWindowImpl->mpBorderWindow.get())->GetBorderStyle(); + else + return mpWindowImpl->mpBorderWindow->GetBorderStyle(); + } + + return WindowBorderStyle::NONE; +} + +tools::Long Window::CalcTitleWidth() const +{ + + if ( mpWindowImpl->mpBorderWindow ) + { + if ( mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW ) + return static_cast(mpWindowImpl->mpBorderWindow.get())->CalcTitleWidth(); + else + return mpWindowImpl->mpBorderWindow->CalcTitleWidth(); + } + else if ( mpWindowImpl->mbFrame && (mpWindowImpl->mnStyle & WB_MOVEABLE) ) + { + // we guess the width for frame windows as we do not know the + // border of external dialogs + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = GetFont(); + const_cast(this)->SetPointFont(const_cast<::OutputDevice&>(*GetOutDev()), rStyleSettings.GetTitleFont()); + tools::Long nTitleWidth = GetTextWidth( GetText() ); + const_cast(this)->SetFont( aFont ); + nTitleWidth += rStyleSettings.GetTitleHeight() * 3; + nTitleWidth += StyleSettings::GetBorderSize() * 2; + nTitleWidth += 10; + return nTitleWidth; + } + + return 0; +} + +void Window::SetInputContext( const InputContext& rInputContext ) +{ + + mpWindowImpl->maInputContext = rInputContext; + if ( !mpWindowImpl->mbInFocusHdl && HasFocus() ) + ImplNewInputContext(); +} + +void Window::PostExtTextInputEvent(VclEventId nType, const OUString& rText) +{ + switch (nType) + { + case VclEventId::ExtTextInput: + { + std::unique_ptr pAttr(new ExtTextInputAttr[rText.getLength()]); + for (int i = 0; i < rText.getLength(); ++i) { + pAttr[i] = ExtTextInputAttr::Underline; + } + SalExtTextInputEvent aEvent { rText, pAttr.get(), rText.getLength(), EXTTEXTINPUT_CURSOR_OVERWRITE }; + ImplWindowFrameProc(this, SalEvent::ExtTextInput, &aEvent); + } + break; + case VclEventId::EndExtTextInput: + ImplWindowFrameProc(this, SalEvent::EndExtTextInput, nullptr); + break; + default: + assert(false); + } +} + +void Window::EndExtTextInput() +{ + if ( mpWindowImpl->mbExtTextInput ) + ImplGetFrame()->EndExtTextInput( EndExtTextInputFlags::Complete ); +} + +void Window::SetCursorRect( const tools::Rectangle* pRect, tools::Long nExtTextInputWidth ) +{ + + ImplWinData* pWinData = ImplGetWinData(); + if ( pWinData->mpCursorRect ) + { + if ( pRect ) + pWinData->mpCursorRect = *pRect; + else + pWinData->mpCursorRect.reset(); + } + else + { + if ( pRect ) + pWinData->mpCursorRect = *pRect; + } + + pWinData->mnCursorExtWidth = nExtTextInputWidth; + +} + +const tools::Rectangle* Window::GetCursorRect() const +{ + + ImplWinData* pWinData = ImplGetWinData(); + return pWinData->mpCursorRect ? &*pWinData->mpCursorRect : nullptr; +} + +tools::Long Window::GetCursorExtTextInputWidth() const +{ + + ImplWinData* pWinData = ImplGetWinData(); + return pWinData->mnCursorExtWidth; +} + +void Window::SetCompositionCharRect( const tools::Rectangle* pRect, tools::Long nCompositionLength, bool bVertical ) { + + ImplWinData* pWinData = ImplGetWinData(); + pWinData->mpCompositionCharRects.reset(); + pWinData->mbVertical = bVertical; + pWinData->mnCompositionCharRects = nCompositionLength; + if ( pRect && (nCompositionLength > 0) ) + { + pWinData->mpCompositionCharRects.reset( new tools::Rectangle[nCompositionLength] ); + for (tools::Long i = 0; i < nCompositionLength; ++i) + pWinData->mpCompositionCharRects[i] = pRect[i]; + } +} + +void Window::CollectChildren(::std::vector& rAllChildren ) +{ + rAllChildren.push_back( this ); + + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->CollectChildren( rAllChildren ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +void Window::SetPointFont(vcl::RenderContext& rRenderContext, const vcl::Font& rFont) +{ + vcl::Font aFont = rFont; + ImplPointToLogic(rRenderContext, aFont); + rRenderContext.SetFont(aFont); +} + +vcl::Font Window::GetPointFont(vcl::RenderContext const & rRenderContext) const +{ + vcl::Font aFont = rRenderContext.GetFont(); + ImplLogicToPoint(rRenderContext, aFont); + return aFont; +} + +void Window::Show(bool bVisible, ShowFlags nFlags) +{ + if ( !mpWindowImpl || mpWindowImpl->mbVisible == bVisible ) + return; + + VclPtr xWindow(this); + + bool bRealVisibilityChanged = false; + mpWindowImpl->mbVisible = bVisible; + + if ( !bVisible ) + { + ImplHideAllOverlaps(); + if( !xWindow->mpWindowImpl ) + return; + + if ( mpWindowImpl->mpBorderWindow ) + { + bool bOldUpdate = mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate; + if ( mpWindowImpl->mbNoParentUpdate ) + mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate = true; + mpWindowImpl->mpBorderWindow->Show( false, nFlags ); + mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate = bOldUpdate; + } + else if ( mpWindowImpl->mbFrame ) + { + mpWindowImpl->mbSuppressAccessibilityEvents = true; + mpWindowImpl->mpFrame->Show( false ); + } + + CompatStateChanged( StateChangedType::Visible ); + + if ( mpWindowImpl->mbReallyVisible ) + { + if ( mpWindowImpl->mbInitWinClipRegion ) + ImplInitWinClipRegion(); + + vcl::Region aInvRegion = mpWindowImpl->maWinClipRegion; + + if( !xWindow->mpWindowImpl ) + return; + + bRealVisibilityChanged = mpWindowImpl->mbReallyVisible; + ImplResetReallyVisible(); + ImplSetClipFlag(); + + if ( ImplIsOverlapWindow() && !mpWindowImpl->mbFrame ) + { + // convert focus + if ( !(nFlags & ShowFlags::NoFocusChange) && HasChildPathFocus() ) + { + if ( mpWindowImpl->mpOverlapWindow->IsEnabled() && + mpWindowImpl->mpOverlapWindow->IsInputEnabled() && + ! mpWindowImpl->mpOverlapWindow->IsInModalMode() + ) + mpWindowImpl->mpOverlapWindow->GrabFocus(); + } + } + + if ( !mpWindowImpl->mbFrame ) + { + if (mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mbEnableNativeWidget) + { + /* + * #i48371# native theming: some themes draw outside the control + * area we tell them to (bad thing, but we cannot do much about it ). + * On hiding these controls they get invalidated with their window rectangle + * which leads to the parts outside the control area being left and not + * invalidated. Workaround: invalidate an area on the parent, too + */ + const int workaround_border = 5; + tools::Rectangle aBounds( aInvRegion.GetBoundRect() ); + aBounds.AdjustLeft( -workaround_border ); + aBounds.AdjustTop( -workaround_border ); + aBounds.AdjustRight(workaround_border ); + aBounds.AdjustBottom(workaround_border ); + aInvRegion = aBounds; + } + if ( !mpWindowImpl->mbNoParentUpdate ) + { + if ( !aInvRegion.IsEmpty() ) + ImplInvalidateParentFrameRegion( aInvRegion ); + } + ImplGenerateMouseMove(); + } + } + } + else + { + // inherit native widget flag for form controls + // required here, because frames never show up in the child hierarchy - which should be fixed... + // eg, the drop down of a combobox which is a system floating window + if( mpWindowImpl->mbFrame && GetParent() && !GetParent()->isDisposed() && + GetParent()->IsCompoundControl() && + GetParent()->IsNativeWidgetEnabled() != IsNativeWidgetEnabled() && + !(GetStyle() & WB_TOOLTIPWIN) ) + { + EnableNativeWidget( GetParent()->IsNativeWidgetEnabled() ); + } + + if ( mpWindowImpl->mbCallMove ) + { + ImplCallMove(); + } + if ( mpWindowImpl->mbCallResize ) + { + ImplCallResize(); + } + + CompatStateChanged( StateChangedType::Visible ); + + vcl::Window* pTestParent; + if ( ImplIsOverlapWindow() ) + pTestParent = mpWindowImpl->mpOverlapWindow; + else + pTestParent = ImplGetParent(); + if ( mpWindowImpl->mbFrame || pTestParent->mpWindowImpl->mbReallyVisible ) + { + // if a window becomes visible, send all child windows a StateChange, + // such that these can initialise themselves + ImplCallInitShow(); + + // If it is a SystemWindow it automatically pops up on top of + // all other windows if needed. + if ( ImplIsOverlapWindow() && !(nFlags & ShowFlags::NoActivate) ) + { + ImplStartToTop(( nFlags & ShowFlags::ForegroundTask ) ? ToTopFlags::ForegroundTask : ToTopFlags::NONE ); + ImplFocusToTop( ToTopFlags::NONE, false ); + } + + // adjust mpWindowImpl->mbReallyVisible + bRealVisibilityChanged = !mpWindowImpl->mbReallyVisible; + ImplSetReallyVisible(); + + // assure clip rectangles will be recalculated + ImplSetClipFlag(); + + if ( !mpWindowImpl->mbFrame ) + { + InvalidateFlags nInvalidateFlags = InvalidateFlags::Children; + if( ! IsPaintTransparent() ) + nInvalidateFlags |= InvalidateFlags::NoTransparent; + ImplInvalidate( nullptr, nInvalidateFlags ); + ImplGenerateMouseMove(); + } + } + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->Show( true, nFlags ); + else if ( mpWindowImpl->mbFrame ) + { + // #106431#, hide SplashScreen + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->mpIntroWindow ) + { + // The right way would be just to call this (not even in the 'if') + auto pApp = GetpApp(); + if ( pApp ) + pApp->InitFinished(); + } + else if ( !ImplIsWindowOrChild( pSVData->mpIntroWindow ) ) + { + // ... but the VCL splash is broken, and it needs this + // (for ./soffice .uno:NewDoc) + pSVData->mpIntroWindow->Hide(); + } + + //SAL_WARN_IF( mpWindowImpl->mbSuppressAccessibilityEvents, "vcl", "Window::Show() - Frame reactivated"); + mpWindowImpl->mbSuppressAccessibilityEvents = false; + + mpWindowImpl->mbPaintFrame = true; + if (!Application::IsHeadlessModeEnabled()) + { + bool bNoActivate(nFlags & (ShowFlags::NoActivate|ShowFlags::NoFocusChange)); + mpWindowImpl->mpFrame->Show( true, bNoActivate ); + } + if( !xWindow->mpWindowImpl ) + return; + + // Query the correct size of the window, if we are waiting for + // a system resize + if ( mpWindowImpl->mbWaitSystemResize ) + { + tools::Long nOutWidth; + tools::Long nOutHeight; + mpWindowImpl->mpFrame->GetClientSize( nOutWidth, nOutHeight ); + ImplHandleResize( this, nOutWidth, nOutHeight ); + } + + if (mpWindowImpl->mpFrameData->mpBuffer && mpWindowImpl->mpFrameData->mpBuffer->GetOutputSizePixel() != GetOutputSizePixel()) + // Make sure that the buffer size matches the window size, even if no resize was needed. + mpWindowImpl->mpFrameData->mpBuffer->SetOutputSizePixel(GetOutputSizePixel()); + } + + if( !xWindow->mpWindowImpl ) + return; + + ImplShowAllOverlaps(); + } + + if( !xWindow->mpWindowImpl ) + return; + + // the SHOW/HIDE events also serve as indicators to send child creation/destroy events to the access bridge + // However, the access bridge only uses this event if the data member is not NULL (it's kind of a hack that + // we re-use the SHOW/HIDE events this way, with this particular semantics). + // Since #104887#, the notifications for the access bridge are done in Impl(Set|Reset)ReallyVisible. Here, we + // now only notify with a NULL data pointer, for all other clients except the access bridge. + if ( !bRealVisibilityChanged ) + CallEventListeners( mpWindowImpl->mbVisible ? VclEventId::WindowShow : VclEventId::WindowHide ); + if( xWindow->isDisposed() ) + return; + +} + +Size Window::GetSizePixel() const +{ + if (!mpWindowImpl) + { + SAL_WARN("vcl.layout", "WTF no windowimpl"); + return Size(0,0); + } + + // #i43257# trigger pending resize handler to assure correct window sizes + if( mpWindowImpl->mpFrameData->maResizeIdle.IsActive() ) + { + VclPtr xWindow( const_cast(this) ); + mpWindowImpl->mpFrameData->maResizeIdle.Stop(); + mpWindowImpl->mpFrameData->maResizeIdle.Invoke( nullptr ); + if( xWindow->isDisposed() ) + return Size(0,0); + } + + return Size( GetOutDev()->mnOutWidth + mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder, + GetOutDev()->mnOutHeight + mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder ); +} + +void Window::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + rLeftBorder = mpWindowImpl->mnLeftBorder; + rTopBorder = mpWindowImpl->mnTopBorder; + rRightBorder = mpWindowImpl->mnRightBorder; + rBottomBorder = mpWindowImpl->mnBottomBorder; +} + +void Window::Enable( bool bEnable, bool bChild ) +{ + if ( isDisposed() ) + return; + + if ( !bEnable ) + { + // the tracking mode will be stopped or the capture will be stolen + // when a window is disabled, + if ( IsTracking() ) + EndTracking( TrackingEventFlags::Cancel ); + if ( IsMouseCaptured() ) + ReleaseMouse(); + // try to pass focus to the next control + // if the window has focus and is contained in the dialog control + // mpWindowImpl->mbDisabled should only be set after a call of ImplDlgCtrlNextWindow(). + // Otherwise ImplDlgCtrlNextWindow() should be used + if ( HasFocus() ) + ImplDlgCtrlNextWindow(); + } + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->Enable( bEnable, false ); + if ( (mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW) && + static_cast(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow ) + static_cast(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow->Enable( bEnable ); + } + + // #i56102# restore app focus win in case the + // window was disabled when the frame focus changed + ImplSVData* pSVData = ImplGetSVData(); + if (bEnable && pSVData->mpWinData->mpFocusWin == nullptr + && mpWindowImpl->mpFrameData->mbHasFocus && mpWindowImpl->mpFrameData->mpFocusWin == this) + pSVData->mpWinData->mpFocusWin = this; + + if ( mpWindowImpl->mbDisabled != !bEnable ) + { + mpWindowImpl->mbDisabled = !bEnable; + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->Enable( bEnable && !mpWindowImpl->mbInputDisabled ); + CompatStateChanged( StateChangedType::Enable ); + + CallEventListeners( bEnable ? VclEventId::WindowEnabled : VclEventId::WindowDisabled ); + } + + if ( bChild ) + { + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->Enable( bEnable, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } + + if ( IsReallyVisible() ) + ImplGenerateMouseMove(); +} + +void Window::EnableInput( bool bEnable, bool bChild ) +{ + if (!mpWindowImpl) + return; + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->EnableInput( bEnable, false ); + if ( (mpWindowImpl->mpBorderWindow->GetType() == WindowType::BORDERWINDOW) && + static_cast(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow ) + static_cast(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow->EnableInput( bEnable ); + } + + if ( (!bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled) || bEnable ) + { + // automatically stop the tracking mode or steal capture + // if the window is disabled + if ( !bEnable ) + { + if ( IsTracking() ) + EndTracking( TrackingEventFlags::Cancel ); + if ( IsMouseCaptured() ) + ReleaseMouse(); + } + + if ( mpWindowImpl->mbInputDisabled != !bEnable ) + { + mpWindowImpl->mbInputDisabled = !bEnable; + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->Enable( !mpWindowImpl->mbDisabled && bEnable ); + } + } + + // #i56102# restore app focus win in case the + // window was disabled when the frame focus changed + ImplSVData* pSVData = ImplGetSVData(); + if (bEnable && pSVData->mpWinData->mpFocusWin == nullptr + && mpWindowImpl->mpFrameData->mbHasFocus && mpWindowImpl->mpFrameData->mpFocusWin == this) + pSVData->mpWinData->mpFocusWin = this; + + if ( bChild ) + { + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->EnableInput( bEnable, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } + + if ( IsReallyVisible() ) + ImplGenerateMouseMove(); +} + +void Window::EnableInput( bool bEnable, const vcl::Window* pExcludeWindow ) +{ + if (!mpWindowImpl) + return; + + EnableInput( bEnable ); + + // pExecuteWindow is the first Overlap-Frame --> if this + // shouldn't be the case, then this must be changed in dialog.cxx + if( pExcludeWindow ) + pExcludeWindow = pExcludeWindow->ImplGetFirstOverlapWindow(); + vcl::Window* pSysWin = mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mpFirstOverlap; + while ( pSysWin ) + { + // Is Window in the path from this window + if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( pSysWin, true ) ) + { + // Is Window not in the exclude window path or not the + // exclude window, then change the status + if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( pSysWin, true ) ) + pSysWin->EnableInput( bEnable ); + } + pSysWin = pSysWin->mpWindowImpl->mpNextOverlap; + } + + // enable/disable floating system windows as well + vcl::Window* pFrameWin = ImplGetSVData()->maFrameData.mpFirstFrame; + while ( pFrameWin ) + { + if( pFrameWin->ImplIsFloatingWindow() ) + { + // Is Window in the path from this window + if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( pFrameWin, true ) ) + { + // Is Window not in the exclude window path or not the + // exclude window, then change the status + if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( pFrameWin, true ) ) + pFrameWin->EnableInput( bEnable ); + } + } + pFrameWin = pFrameWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + + // the same for ownerdraw floating windows + if( !mpWindowImpl->mbFrame ) + return; + + ::std::vector< VclPtr >& rList = mpWindowImpl->mpFrameData->maOwnerDrawList; + for (auto const& elem : rList) + { + // Is Window in the path from this window + if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( elem, true ) ) + { + // Is Window not in the exclude window path or not the + // exclude window, then change the status + if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( elem, true ) ) + elem->EnableInput( bEnable ); + } + } +} + +void Window::AlwaysEnableInput( bool bAlways, bool bChild ) +{ + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->AlwaysEnableInput( bAlways, false ); + + if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled ) + { + mpWindowImpl->meAlwaysInputMode = AlwaysInputEnabled; + EnableInput(true, false); + } + else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputEnabled ) + { + mpWindowImpl->meAlwaysInputMode = AlwaysInputNone; + } + + if ( bChild ) + { + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->AlwaysEnableInput( bAlways, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +void Window::SetActivateMode( ActivateModeFlags nMode ) +{ + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetActivateMode( nMode ); + + if ( mpWindowImpl->mnActivateMode == nMode ) + return; + + mpWindowImpl->mnActivateMode = nMode; + + // possibly trigger Deactivate/Activate + if ( mpWindowImpl->mnActivateMode != ActivateModeFlags::NONE ) + { + if ( (mpWindowImpl->mbActive || (GetType() == WindowType::BORDERWINDOW)) && + !HasChildPathFocus( true ) ) + { + mpWindowImpl->mbActive = false; + Deactivate(); + } + } + else + { + if ( !mpWindowImpl->mbActive || (GetType() == WindowType::BORDERWINDOW) ) + { + mpWindowImpl->mbActive = true; + Activate(); + } + } +} + +void Window::setPosSizePixel( tools::Long nX, tools::Long nY, + tools::Long nWidth, tools::Long nHeight, PosSizeFlags nFlags ) +{ + bool bHasValidSize = !mpWindowImpl->mbDefSize; + + if ( nFlags & PosSizeFlags::Pos ) + mpWindowImpl->mbDefPos = false; + if ( nFlags & PosSizeFlags::Size ) + mpWindowImpl->mbDefSize = false; + + // The top BorderWindow is the window which is to be positioned + VclPtr pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + + if ( pWindow->mpWindowImpl->mbFrame ) + { + // Note: if we're positioning a frame, the coordinates are interpreted + // as being the top-left corner of the window's client area and NOT + // as the position of the border ! (due to limitations of several UNIX window managers) + tools::Long nOldWidth = pWindow->GetOutDev()->mnOutWidth; + + if ( !(nFlags & PosSizeFlags::Width) ) + nWidth = pWindow->GetOutDev()->mnOutWidth; + if ( !(nFlags & PosSizeFlags::Height) ) + nHeight = pWindow->GetOutDev()->mnOutHeight; + + sal_uInt16 nSysFlags=0; + VclPtr pParent = GetParent(); + VclPtr pWinParent = pWindow->GetParent(); + + if( nFlags & PosSizeFlags::Width ) + nSysFlags |= SAL_FRAME_POSSIZE_WIDTH; + if( nFlags & PosSizeFlags::Height ) + nSysFlags |= SAL_FRAME_POSSIZE_HEIGHT; + if( nFlags & PosSizeFlags::X ) + { + nSysFlags |= SAL_FRAME_POSSIZE_X; + if( pWinParent && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) ) + { + nX += pWinParent->GetOutDev()->mnOutOffX; + } + if( pParent && pParent->GetOutDev()->ImplIsAntiparallel() ) + { + tools::Rectangle aRect( Point ( nX, nY ), Size( nWidth, nHeight ) ); + const OutputDevice *pParentOutDev = pParent->GetOutDev(); + if (!comphelper::LibreOfficeKit::isActive()) + pParentOutDev->ReMirror( aRect ); + nX = aRect.Left(); + } + } + if( !comphelper::LibreOfficeKit::isActive() && + !(nFlags & PosSizeFlags::X) && bHasValidSize && + pWindow->mpWindowImpl->mpFrame->maGeometry.nWidth ) + { + // RTL: make sure the old right aligned position is not changed + // system windows will always grow to the right + if ( pWinParent ) + { + OutputDevice *pParentOutDev = pWinParent->GetOutDev(); + if( pParentOutDev->HasMirroredGraphics() ) + { + const SalFrameGeometry& aSysGeometry = mpWindowImpl->mpFrame->GetUnmirroredGeometry(); + const SalFrameGeometry& aParentSysGeometry = + pWinParent->mpWindowImpl->mpFrame->GetUnmirroredGeometry(); + tools::Long myWidth = nOldWidth; + if( !myWidth ) + myWidth = aSysGeometry.nWidth; + if( !myWidth ) + myWidth = nWidth; + nFlags |= PosSizeFlags::X; + nSysFlags |= SAL_FRAME_POSSIZE_X; + nX = aParentSysGeometry.nX - aSysGeometry.nLeftDecoration + aParentSysGeometry.nWidth + - myWidth - 1 - aSysGeometry.nX; + } + } + } + if( nFlags & PosSizeFlags::Y ) + { + nSysFlags |= SAL_FRAME_POSSIZE_Y; + if( pWinParent && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) ) + { + nY += pWinParent->GetOutDev()->mnOutOffY; + } + } + + if( nSysFlags & (SAL_FRAME_POSSIZE_WIDTH|SAL_FRAME_POSSIZE_HEIGHT) ) + { + // check for min/max client size and adjust size accordingly + // otherwise it may happen that the resize event is ignored, i.e. the old size remains + // unchanged but ImplHandleResize() is called with the wrong size + SystemWindow *pSystemWindow = dynamic_cast< SystemWindow* >( pWindow.get() ); + if( pSystemWindow ) + { + Size aMinSize = pSystemWindow->GetMinOutputSizePixel(); + Size aMaxSize = pSystemWindow->GetMaxOutputSizePixel(); + if( nWidth < aMinSize.Width() ) + nWidth = aMinSize.Width(); + if( nHeight < aMinSize.Height() ) + nHeight = aMinSize.Height(); + + if( nWidth > aMaxSize.Width() ) + nWidth = aMaxSize.Width(); + if( nHeight > aMaxSize.Height() ) + nHeight = aMaxSize.Height(); + } + } + + pWindow->mpWindowImpl->mpFrame->SetPosSize( nX, nY, nWidth, nHeight, nSysFlags ); + + // Adjust resize with the hack of different client size and frame geometries to fix + // native menu bars. Eventually this should be replaced by proper mnTopBorder usage. + pWindow->mpWindowImpl->mpFrame->GetClientSize(nWidth, nHeight); + + // Resize should be called directly. If we haven't + // set the correct size, we get a second resize from + // the system with the correct size. This can be happened + // if the size is too small or too large. + ImplHandleResize( pWindow, nWidth, nHeight ); + } + else + { + pWindow->ImplPosSizeWindow( nX, nY, nWidth, nHeight, nFlags ); + if ( IsReallyVisible() ) + ImplGenerateMouseMove(); + } +} + +Point Window::GetPosPixel() const +{ + return mpWindowImpl->maPos; +} + +tools::Rectangle Window::GetDesktopRectPixel() const +{ + tools::Rectangle rRect; + mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrame->GetWorkArea( rRect ); + return rRect; +} + +Point Window::OutputToScreenPixel( const Point& rPos ) const +{ + // relative to top level parent + return Point( rPos.X() + GetOutDev()->mnOutOffX, rPos.Y() + GetOutDev()->mnOutOffY ); +} + +Point Window::ScreenToOutputPixel( const Point& rPos ) const +{ + // relative to top level parent + return Point( rPos.X() - GetOutDev()->mnOutOffX, rPos.Y() - GetOutDev()->mnOutOffY ); +} + +tools::Long Window::ImplGetUnmirroredOutOffX() +{ + // revert mnOutOffX changes that were potentially made in ImplPosSizeWindow + tools::Long offx = GetOutDev()->mnOutOffX; + OutputDevice *pOutDev = GetOutDev(); + if( pOutDev->HasMirroredGraphics() ) + { + if( mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->GetOutDev()->ImplIsAntiparallel() ) + { + if ( !ImplIsOverlapWindow() ) + offx -= mpWindowImpl->mpParent->GetOutDev()->mnOutOffX; + + offx = mpWindowImpl->mpParent->GetOutDev()->mnOutWidth - GetOutDev()->mnOutWidth - offx; + + if ( !ImplIsOverlapWindow() ) + offx += mpWindowImpl->mpParent->GetOutDev()->mnOutOffX; + + } + } + return offx; +} + +// normalized screen pixel are independent of mirroring +Point Window::OutputToNormalizedScreenPixel( const Point& rPos ) const +{ + // relative to top level parent + tools::Long offx = const_cast(this)->ImplGetUnmirroredOutOffX(); + return Point( rPos.X()+offx, rPos.Y() + GetOutDev()->mnOutOffY ); +} + +Point Window::NormalizedScreenToOutputPixel( const Point& rPos ) const +{ + // relative to top level parent + tools::Long offx = const_cast(this)->ImplGetUnmirroredOutOffX(); + return Point( rPos.X()-offx, rPos.Y() - GetOutDev()->mnOutOffY ); +} + +Point Window::OutputToAbsoluteScreenPixel( const Point& rPos ) const +{ + // relative to the screen + Point p = OutputToScreenPixel( rPos ); + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + p.AdjustX(g.nX ); + p.AdjustY(g.nY ); + return p; +} + +Point Window::AbsoluteScreenToOutputPixel( const Point& rPos ) const +{ + // relative to the screen + Point p = ScreenToOutputPixel( rPos ); + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + p.AdjustX( -(g.nX) ); + p.AdjustY( -(g.nY) ); + return p; +} + +tools::Rectangle Window::ImplOutputToUnmirroredAbsoluteScreenPixel( const tools::Rectangle &rRect ) const +{ + // this method creates unmirrored screen coordinates to be compared with the desktop + // and is used for positioning of RTL popup windows correctly on the screen + SalFrameGeometry g = mpWindowImpl->mpFrame->GetUnmirroredGeometry(); + + Point p1 = rRect.TopRight(); + p1 = OutputToScreenPixel(p1); + p1.setX( g.nX+g.nWidth-p1.X() ); + p1.AdjustY(g.nY ); + + Point p2 = rRect.BottomLeft(); + p2 = OutputToScreenPixel(p2); + p2.setX( g.nX+g.nWidth-p2.X() ); + p2.AdjustY(g.nY ); + + return tools::Rectangle( p1, p2 ); +} + +tools::Rectangle Window::ImplUnmirroredAbsoluteScreenToOutputPixel( const tools::Rectangle &rRect ) const +{ + // undo ImplOutputToUnmirroredAbsoluteScreenPixel + SalFrameGeometry g = mpWindowImpl->mpFrame->GetUnmirroredGeometry(); + + Point p1 = rRect.TopRight(); + p1.AdjustY(-g.nY ); + p1.setX( g.nX+g.nWidth-p1.X() ); + p1 = ScreenToOutputPixel(p1); + + Point p2 = rRect.BottomLeft(); + p2.AdjustY(-g.nY); + p2.setX( g.nX+g.nWidth-p2.X() ); + p2 = ScreenToOutputPixel(p2); + + return tools::Rectangle( p1, p2 ); +} + + +tools::Rectangle Window::GetWindowExtentsRelative(const vcl::Window *pRelativeWindow) const +{ + // with decoration + return ImplGetWindowExtentsRelative( pRelativeWindow ); +} + +tools::Rectangle Window::ImplGetWindowExtentsRelative(const vcl::Window *pRelativeWindow) const +{ + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + // make sure we use the extent of our border window, + // otherwise we miss a few pixels + const vcl::Window *pWin = mpWindowImpl->mpBorderWindow ? mpWindowImpl->mpBorderWindow : this; + + Point aPos( pWin->OutputToScreenPixel( Point(0,0) ) ); + aPos.AdjustX(g.nX ); + aPos.AdjustY(g.nY ); + Size aSize ( pWin->GetSizePixel() ); + // #104088# do not add decoration to the workwindow to be compatible to java accessibility api + if( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame && GetType() != WindowType::WORKWINDOW) ) + { + aPos.AdjustX( -sal_Int32(g.nLeftDecoration) ); + aPos.AdjustY( -sal_Int32(g.nTopDecoration) ); + aSize.AdjustWidth(g.nLeftDecoration + g.nRightDecoration ); + aSize.AdjustHeight(g.nTopDecoration + g.nBottomDecoration ); + } + if( pRelativeWindow ) + { + // #106399# express coordinates relative to borderwindow + const vcl::Window *pRelWin = pRelativeWindow->mpWindowImpl->mpBorderWindow ? pRelativeWindow->mpWindowImpl->mpBorderWindow.get() : pRelativeWindow; + aPos = pRelWin->AbsoluteScreenToOutputPixel( aPos ); + } + return tools::Rectangle( aPos, aSize ); +} + +void Window::Scroll( tools::Long nHorzScroll, tools::Long nVertScroll, ScrollFlags nFlags ) +{ + + ImplScroll( GetOutputRectPixel(), + nHorzScroll, nVertScroll, nFlags & ~ScrollFlags::Clip ); +} + +void Window::Scroll( tools::Long nHorzScroll, tools::Long nVertScroll, + const tools::Rectangle& rRect, ScrollFlags nFlags ) +{ + OutputDevice *pOutDev = GetOutDev(); + tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect ); + aRect.Intersection( GetOutputRectPixel() ); + if ( !aRect.IsEmpty() ) + ImplScroll( aRect, nHorzScroll, nVertScroll, nFlags ); +} + +void WindowOutputDevice::Flush() +{ + if (mxOwnerWindow->mpWindowImpl) + mxOwnerWindow->mpWindowImpl->mpFrame->Flush( GetOutputRectPixel() ); +} + +void Window::SetUpdateMode( bool bUpdate ) +{ + if (mpWindowImpl) + { + mpWindowImpl->mbNoUpdate = !bUpdate; + CompatStateChanged( StateChangedType::UpdateMode ); + } +} + +void Window::GrabFocus() +{ + ImplGrabFocus( GetFocusFlags::NONE ); +} + +bool Window::HasFocus() const +{ + return (this == ImplGetSVData()->mpWinData->mpFocusWin); +} + +void Window::GrabFocusToDocument() +{ + ImplGrabFocusToDocument(GetFocusFlags::NONE); +} + +VclPtr Window::GetFocusedWindow() const +{ + if (mpWindowImpl && mpWindowImpl->mpFrameData) + return mpWindowImpl->mpFrameData->mpFocusWin; + else + return VclPtr(); +} + +void Window::SetFakeFocus( bool bFocus ) +{ + ImplGetWindowImpl()->mbFakeFocusSet = bFocus; +} + +bool Window::HasChildPathFocus( bool bSystemWindow ) const +{ + + vcl::Window* pFocusWin = ImplGetSVData()->mpWinData->mpFocusWin; + if ( pFocusWin ) + return ImplIsWindowOrChild( pFocusWin, bSystemWindow ); + return false; +} + +void Window::SetCursor( vcl::Cursor* pCursor ) +{ + + if ( mpWindowImpl->mpCursor != pCursor ) + { + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplHide(); + mpWindowImpl->mpCursor = pCursor; + if ( pCursor ) + pCursor->ImplShow(); + } +} + +void Window::SetText( const OUString& rStr ) +{ + if (!mpWindowImpl || rStr == mpWindowImpl->maText) + return; + + OUString oldTitle( mpWindowImpl->maText ); + mpWindowImpl->maText = rStr; + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetText( rStr ); + else if ( mpWindowImpl->mbFrame ) + mpWindowImpl->mpFrame->SetTitle( rStr ); + + CallEventListeners( VclEventId::WindowFrameTitleChanged, &oldTitle ); + + // #107247# needed for accessibility + // The VclEventId::WindowFrameTitleChanged is (mis)used to notify accessible name changes. + // Therefore a window, which is labeled by this window, must also notify an accessible + // name change. + if ( IsReallyVisible() ) + { + vcl::Window* pWindow = GetAccessibleRelationLabelFor(); + if ( pWindow && pWindow != this ) + pWindow->CallEventListeners( VclEventId::WindowFrameTitleChanged, &oldTitle ); + } + + CompatStateChanged( StateChangedType::Text ); +} + +OUString Window::GetText() const +{ + + return mpWindowImpl->maText; +} + +OUString Window::GetDisplayText() const +{ + + return GetText(); +} + +const Wallpaper& Window::GetDisplayBackground() const +{ + // FIXME: fix issue 52349, need to fix this really in + // all NWF enabled controls + const ToolBox* pTB = dynamic_cast(this); + if( pTB && IsNativeWidgetEnabled() ) + return pTB->ImplGetToolBoxPrivateData()->maDisplayBackground; + + if( !IsBackground() ) + { + if( mpWindowImpl->mpParent ) + return mpWindowImpl->mpParent->GetDisplayBackground(); + } + + const Wallpaper& rBack = GetBackground(); + if( ! rBack.IsBitmap() && + ! rBack.IsGradient() && + rBack.GetColor()== COL_TRANSPARENT && + mpWindowImpl->mpParent ) + return mpWindowImpl->mpParent->GetDisplayBackground(); + return rBack; +} + +const OUString& Window::GetHelpText() const +{ + OUString aStrHelpId( OStringToOUString( GetHelpId(), RTL_TEXTENCODING_UTF8 ) ); + bool bStrHelpId = !aStrHelpId.isEmpty(); + + if ( !mpWindowImpl->maHelpText.getLength() && bStrHelpId ) + { + if ( !IsDialog() && (mpWindowImpl->mnType != WindowType::TABPAGE) && (mpWindowImpl->mnType != WindowType::FLOATINGWINDOW) ) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + mpWindowImpl->maHelpText = pHelp->GetHelpText(aStrHelpId, this); + mpWindowImpl->mbHelpTextDynamic = false; + } + } + } + else if( mpWindowImpl->mbHelpTextDynamic && bStrHelpId ) + { + static const char* pEnv = getenv( "HELP_DEBUG" ); + if( pEnv && *pEnv ) + { + OUString aTxt = mpWindowImpl->maHelpText + "\n------------------\n" + aStrHelpId; + mpWindowImpl->maHelpText = aTxt; + } + mpWindowImpl->mbHelpTextDynamic = false; + } + + //Fallback to Window::GetAccessibleDescription without reentry to GetHelpText() + if (mpWindowImpl->maHelpText.isEmpty() && mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleDescription) + return *mpWindowImpl->mpAccessibleInfos->pAccessibleDescription; + return mpWindowImpl->maHelpText; +} + +void Window::SetWindowPeer( Reference< css::awt::XWindowPeer > const & xPeer, VCLXWindow* pVCLXWindow ) +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + return; + + // be safe against re-entrance: first clear the old ref, then assign the new one + if (mpWindowImpl->mxWindowPeer) + { + // first, disconnect the peer from ourself, otherwise disposing it, will dispose us + UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper(); + SAL_WARN_IF( !pWrapper, "vcl.window", "SetComponentInterface: No Wrapper!" ); + if ( pWrapper ) + pWrapper->SetWindowInterface( nullptr, mpWindowImpl->mxWindowPeer ); + mpWindowImpl->mxWindowPeer->dispose(); + mpWindowImpl->mxWindowPeer.clear(); + } + mpWindowImpl->mxWindowPeer = xPeer; + + mpWindowImpl->mpVCLXWindow = pVCLXWindow; +} + +Reference< css::awt::XWindowPeer > Window::GetComponentInterface( bool bCreate ) +{ + if ( !mpWindowImpl->mxWindowPeer.is() && bCreate ) + { + UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper(); + if ( pWrapper ) + mpWindowImpl->mxWindowPeer = pWrapper->GetWindowInterface( this ); + } + return mpWindowImpl->mxWindowPeer; +} + +void Window::SetComponentInterface( Reference< css::awt::XWindowPeer > const & xIFace ) +{ + UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper(); + SAL_WARN_IF( !pWrapper, "vcl.window", "SetComponentInterface: No Wrapper!" ); + if ( pWrapper ) + pWrapper->SetWindowInterface( this, xIFace ); +} + +typedef std::map> LOKWindowsMap; + +namespace { + +LOKWindowsMap& GetLOKWindowsMap() +{ + // Map to remember the LOKWindowId <-> Window binding. + static LOKWindowsMap s_aLOKWindowsMap; + + return s_aLOKWindowsMap; +} + +} + +void Window::SetLOKNotifier(const vcl::ILibreOfficeKitNotifier* pNotifier, bool bParent) +{ + // don't allow setting this twice + assert(mpWindowImpl->mpLOKNotifier == nullptr); + assert(pNotifier); + // never use this in the desktop case + assert(comphelper::LibreOfficeKit::isActive()); + + if (!bParent) + { + // Counter to be able to have unique id's for each window. + static vcl::LOKWindowId sLastLOKWindowId = 1; + + // assign the LOK window id + assert(mpWindowImpl->mnLOKWindowId == 0); + mpWindowImpl->mnLOKWindowId = sLastLOKWindowId++; + GetLOKWindowsMap().emplace(mpWindowImpl->mnLOKWindowId, this); + } + else + mpWindowImpl->mbLOKParentNotifier = true; + + mpWindowImpl->mpLOKNotifier = pNotifier; +} + +VclPtr Window::FindLOKWindow(vcl::LOKWindowId nWindowId) +{ + const auto it = GetLOKWindowsMap().find(nWindowId); + if (it != GetLOKWindowsMap().end()) + return it->second; + + return VclPtr(); +} + +bool Window::IsLOKWindowsEmpty() +{ + return GetLOKWindowsMap().empty(); +} + +void Window::ReleaseLOKNotifier() +{ + // unregister the LOK window binding + if (mpWindowImpl->mnLOKWindowId > 0) + GetLOKWindowsMap().erase(mpWindowImpl->mnLOKWindowId); + + mpWindowImpl->mpLOKNotifier = nullptr; + mpWindowImpl->mnLOKWindowId = 0; +} + +ILibreOfficeKitNotifier::~ILibreOfficeKitNotifier() +{ + if (!comphelper::LibreOfficeKit::isActive()) + { + return; + } + + for (auto it = GetLOKWindowsMap().begin(); it != GetLOKWindowsMap().end();) + { + WindowImpl* pWindowImpl = it->second->ImplGetWindowImpl(); + if (pWindowImpl && pWindowImpl->mpLOKNotifier == this) + { + pWindowImpl->mpLOKNotifier = nullptr; + pWindowImpl->mnLOKWindowId = 0; + it = GetLOKWindowsMap().erase(it); + continue; + } + + ++it; + } +} + +const vcl::ILibreOfficeKitNotifier* Window::GetLOKNotifier() const +{ + return mpWindowImpl ? mpWindowImpl->mpLOKNotifier : nullptr; +} + +vcl::LOKWindowId Window::GetLOKWindowId() const +{ + return mpWindowImpl ? mpWindowImpl->mnLOKWindowId : 0; +} + +VclPtr Window::GetParentWithLOKNotifier() +{ + VclPtr pWindow(this); + + while (pWindow && !pWindow->GetLOKNotifier()) + pWindow = pWindow->GetParent(); + + return pWindow; +} + +namespace +{ + +const char* windowTypeName(WindowType nWindowType) +{ + switch (nWindowType) + { + case WindowType::NONE: return "none"; + case WindowType::MESSBOX: return "messagebox"; + case WindowType::INFOBOX: return "infobox"; + case WindowType::WARNINGBOX: return "warningbox"; + case WindowType::ERRORBOX: return "errorbox"; + case WindowType::QUERYBOX: return "querybox"; + case WindowType::WINDOW: return "window"; + case WindowType::WORKWINDOW: return "workwindow"; + case WindowType::CONTAINER: return "container"; + case WindowType::FLOATINGWINDOW: return "floatingwindow"; + case WindowType::DIALOG: return "dialog"; + case WindowType::MODELESSDIALOG: return "modelessdialog"; + case WindowType::CONTROL: return "control"; + case WindowType::PUSHBUTTON: return "pushbutton"; + case WindowType::OKBUTTON: return "okbutton"; + case WindowType::CANCELBUTTON: return "cancelbutton"; + case WindowType::HELPBUTTON: return "helpbutton"; + case WindowType::IMAGEBUTTON: return "imagebutton"; + case WindowType::MENUBUTTON: return "menubutton"; + case WindowType::MOREBUTTON: return "morebutton"; + case WindowType::SPINBUTTON: return "spinbutton"; + case WindowType::RADIOBUTTON: return "radiobutton"; + case WindowType::CHECKBOX: return "checkbox"; + case WindowType::TRISTATEBOX: return "tristatebox"; + case WindowType::EDIT: return "edit"; + case WindowType::MULTILINEEDIT: return "multilineedit"; + case WindowType::COMBOBOX: return "combobox"; + case WindowType::LISTBOX: return "listbox"; + case WindowType::MULTILISTBOX: return "multilistbox"; + case WindowType::FIXEDTEXT: return "fixedtext"; + case WindowType::FIXEDLINE: return "fixedline"; + case WindowType::FIXEDBITMAP: return "fixedbitmap"; + case WindowType::FIXEDIMAGE: return "fixedimage"; + case WindowType::GROUPBOX: return "groupbox"; + case WindowType::SCROLLBAR: return "scrollbar"; + case WindowType::SCROLLBARBOX: return "scrollbarbox"; + case WindowType::SPLITTER: return "splitter"; + case WindowType::SPLITWINDOW: return "splitwindow"; + case WindowType::SPINFIELD: return "spinfield"; + case WindowType::PATTERNFIELD: return "patternfield"; + case WindowType::METRICFIELD: return "metricfield"; + case WindowType::FORMATTEDFIELD: return "formattedfield"; + case WindowType::CURRENCYFIELD: return "currencyfield"; + case WindowType::DATEFIELD: return "datefield"; + case WindowType::TIMEFIELD: return "timefield"; + case WindowType::PATTERNBOX: return "patternbox"; + case WindowType::NUMERICBOX: return "numericbox"; + case WindowType::METRICBOX: return "metricbox"; + case WindowType::CURRENCYBOX: return "currencybox"; + case WindowType::DATEBOX: return "datebox"; + case WindowType::TIMEBOX: return "timebox"; + case WindowType::LONGCURRENCYBOX: return "longcurrencybox"; + case WindowType::SCROLLWINDOW: return "scrollwindow"; + case WindowType::TOOLBOX: return "toolbox"; + case WindowType::DOCKINGWINDOW: return "dockingwindow"; + case WindowType::STATUSBAR: return "statusbar"; + case WindowType::TABPAGE: return "tabpage"; + case WindowType::TABCONTROL: return "tabcontrol"; + case WindowType::TABDIALOG: return "tabdialog"; + case WindowType::BORDERWINDOW: return "borderwindow"; + case WindowType::BUTTONDIALOG: return "buttondialog"; + case WindowType::SYSTEMCHILDWINDOW: return "systemchildwindow"; + case WindowType::SLIDER: return "slider"; + case WindowType::MENUBARWINDOW: return "menubarwindow"; + case WindowType::TREELISTBOX: return "treelistbox"; + case WindowType::HELPTEXTWINDOW: return "helptextwindow"; + case WindowType::INTROWINDOW: return "introwindow"; + case WindowType::LISTBOXWINDOW: return "listboxwindow"; + case WindowType::DOCKINGAREA: return "dockingarea"; + case WindowType::RULER: return "ruler"; + case WindowType::HEADERBAR: return "headerbar"; + case WindowType::VERTICALTABCONTROL: return "verticaltabcontrol"; + + // nothing to do here, but for completeness + case WindowType::TOOLKIT_FRAMEWINDOW: return "toolkit_framewindow"; + case WindowType::TOOLKIT_SYSTEMCHILDWINDOW: return "toolkit_systemchildwindow"; + } + + return "none"; +} + +} + +void Window::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) +{ + if (!mpWindowImpl) + return; + + rJsonWriter.put("id", get_id()); // TODO could be missing - sort out + rJsonWriter.put("type", windowTypeName(GetType())); + rJsonWriter.put("text", GetText()); + rJsonWriter.put("enabled", IsEnabled()); + if (!IsVisible()) + rJsonWriter.put("visible", false); + + if (vcl::Window* pChild = mpWindowImpl->mpFirstChild) + { + auto childrenNode = rJsonWriter.startArray("children"); + while (pChild) + { + { + auto childNode = rJsonWriter.startStruct(); + pChild->DumpAsPropertyTree(rJsonWriter); + sal_Int32 nLeft = pChild->get_grid_left_attach(); + sal_Int32 nTop = pChild->get_grid_top_attach(); + if (nLeft != -1 && nTop != -1) + { + rJsonWriter.put("left", nLeft); + rJsonWriter.put("top", nTop); + } + + sal_Int32 nWidth = pChild->get_grid_width(); + if (nWidth > 1) + rJsonWriter.put("width", nWidth); + } + pChild = pChild->mpWindowImpl->mpNext; + } + } + + mpWindowImpl->maDumpAsPropertyTreeHdl.Call(rJsonWriter); +} + +void Window::ImplCallDeactivateListeners( vcl::Window *pNew ) +{ + // no deactivation if the newly activated window is my child + if ( !pNew || !ImplIsChild( pNew ) ) + { + VclPtr xWindow(this); + CallEventListeners( VclEventId::WindowDeactivate, pNew ); + if( !xWindow->mpWindowImpl ) + return; + + // #100759#, avoid walking the wrong frame's hierarchy + // eg, undocked docking windows (ImplDockFloatWin) + if ( ImplGetParent() && ImplGetParent()->mpWindowImpl && + mpWindowImpl->mpFrameWindow == ImplGetParent()->mpWindowImpl->mpFrameWindow ) + ImplGetParent()->ImplCallDeactivateListeners( pNew ); + } +} + +void Window::ImplCallActivateListeners( vcl::Window *pOld ) +{ + // no activation if the old active window is my child + if ( pOld && ImplIsChild( pOld )) + return; + + VclPtr xWindow(this); + CallEventListeners( VclEventId::WindowActivate, pOld ); + if( !xWindow->mpWindowImpl ) + return; + + if ( ImplGetParent() ) + ImplGetParent()->ImplCallActivateListeners( pOld ); + else if( (mpWindowImpl->mnStyle & WB_INTROWIN) == 0 ) + { + // top level frame reached: store hint for DefModalDialogParent + ImplGetSVData()->maFrameData.mpActiveApplicationFrame = mpWindowImpl->mpFrameWindow; + } +} + +void Window::SetClipboard(Reference const & xClipboard) +{ + if (mpWindowImpl->mpFrameData) + mpWindowImpl->mpFrameData->mxClipboard = xClipboard; +} + +Reference< XClipboard > Window::GetClipboard() +{ + if (!mpWindowImpl->mpFrameData) + return static_cast(nullptr); + if (!mpWindowImpl->mpFrameData->mxClipboard.is()) + mpWindowImpl->mpFrameData->mxClipboard = GetSystemClipboard(); + return mpWindowImpl->mpFrameData->mxClipboard; +} + +void Window::RecordLayoutData( vcl::ControlLayoutData* pLayout, const tools::Rectangle& rRect ) +{ + assert(GetOutDev()->mpOutDevData); + GetOutDev()->mpOutDevData->mpRecordLayout = pLayout; + GetOutDev()->mpOutDevData->maRecordRect = rRect; + Paint(*GetOutDev(), rRect); + GetOutDev()->mpOutDevData->mpRecordLayout = nullptr; +} + +void Window::DrawSelectionBackground( const tools::Rectangle& rRect, + sal_uInt16 highlight, + bool bChecked, + bool bDrawBorder + ) +{ + if( rRect.IsEmpty() ) + return; + + const StyleSettings& rStyles = GetSettings().GetStyleSettings(); + + // colors used for item highlighting + Color aSelectionBorderCol( rStyles.GetHighlightColor() ); + Color aSelectionFillCol( aSelectionBorderCol ); + + bool bDark = rStyles.GetFaceColor().IsDark(); + bool bBright = ( rStyles.GetFaceColor() == COL_WHITE ); + + int c1 = aSelectionBorderCol.GetLuminance(); + int c2 = GetBackgroundColor().GetLuminance(); + + if( !bDark && !bBright && abs( c2-c1 ) < 75 ) + { + // contrast too low + sal_uInt16 h,s,b; + aSelectionFillCol.RGBtoHSB( h, s, b ); + if( b > 50 ) b -= 40; + else b += 40; + aSelectionFillCol = Color::HSBtoRGB( h, s, b ); + aSelectionBorderCol = aSelectionFillCol; + } + + tools::Rectangle aRect( rRect ); + Color oldFillCol = GetOutDev()->GetFillColor(); + Color oldLineCol = GetOutDev()->GetLineColor(); + + if( bDrawBorder ) + GetOutDev()->SetLineColor( bDark ? COL_WHITE : ( bBright ? COL_BLACK : aSelectionBorderCol ) ); + else + GetOutDev()->SetLineColor(); + + sal_uInt16 nPercent = 0; + if( !highlight ) + { + if( bDark ) + aSelectionFillCol = COL_BLACK; + else + nPercent = 80; // just checked (light) + } + else + { + if( bChecked && highlight == 2 ) + { + if( bDark ) + aSelectionFillCol = COL_LIGHTGRAY; + else if ( bBright ) + { + aSelectionFillCol = COL_BLACK; + GetOutDev()->SetLineColor( COL_BLACK ); + nPercent = 0; + } + else + nPercent = 20; // selected, pressed or checked ( very dark ) + } + else if( bChecked || highlight == 1 ) + { + if( bDark ) + aSelectionFillCol = COL_GRAY; + else if ( bBright ) + { + aSelectionFillCol = COL_BLACK; + GetOutDev()->SetLineColor( COL_BLACK ); + nPercent = 0; + } + else + nPercent = 35; // selected, pressed or checked ( very dark ) + } + else + { + if( bDark ) + aSelectionFillCol = COL_LIGHTGRAY; + else if ( bBright ) + { + aSelectionFillCol = COL_BLACK; + GetOutDev()->SetLineColor( COL_BLACK ); + if( highlight == 3 ) + nPercent = 80; + else + nPercent = 0; + } + else + nPercent = 70; // selected ( dark ) + } + } + + GetOutDev()->SetFillColor( aSelectionFillCol ); + + if( bDark ) + { + GetOutDev()->DrawRect( aRect ); + } + else + { + tools::Polygon aPoly( aRect ); + tools::PolyPolygon aPolyPoly( aPoly ); + GetOutDev()->DrawTransparent( aPolyPoly, nPercent ); + } + + GetOutDev()->SetFillColor( oldFillCol ); + GetOutDev()->SetLineColor( oldLineCol ); +} + +bool Window::IsScrollable() const +{ + // check for scrollbars + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while( pChild ) + { + if( pChild->GetType() == WindowType::SCROLLBAR ) + return true; + else + pChild = pChild->mpWindowImpl->mpNext; + } + return false; +} + +void Window::ImplMirrorFramePos( Point &pt ) const +{ + pt.setX( mpWindowImpl->mpFrame->maGeometry.nWidth-1-pt.X() ); +} + +// frame based modal counter (dialogs are not modal to the whole application anymore) +bool Window::IsInModalMode() const +{ + return (mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mnModalMode != 0); +} + +void Window::IncModalCount() +{ + vcl::Window* pFrameWindow = mpWindowImpl->mpFrameWindow; + vcl::Window* pParent = pFrameWindow; + while( pFrameWindow ) + { + pFrameWindow->mpWindowImpl->mpFrameData->mnModalMode++; + while( pParent && pParent->mpWindowImpl->mpFrameWindow == pFrameWindow ) + { + pParent = pParent->GetParent(); + } + pFrameWindow = pParent ? pParent->mpWindowImpl->mpFrameWindow.get() : nullptr; + } +} +void Window::DecModalCount() +{ + vcl::Window* pFrameWindow = mpWindowImpl->mpFrameWindow; + vcl::Window* pParent = pFrameWindow; + while( pFrameWindow ) + { + pFrameWindow->mpWindowImpl->mpFrameData->mnModalMode--; + while( pParent && pParent->mpWindowImpl->mpFrameWindow == pFrameWindow ) + { + pParent = pParent->GetParent(); + } + pFrameWindow = pParent ? pParent->mpWindowImpl->mpFrameWindow.get() : nullptr; + } +} + +void Window::ImplIsInTaskPaneList( bool mbIsInTaskList ) +{ + mpWindowImpl->mbIsInTaskPaneList = mbIsInTaskList; +} + +void Window::ImplNotifyIconifiedState( bool bIconified ) +{ + mpWindowImpl->mpFrameWindow->CallEventListeners( bIconified ? VclEventId::WindowMinimize : VclEventId::WindowNormalize ); + // #109206# notify client window as well to have toolkit topwindow listeners notified + if( mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow && mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow ) + mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow->CallEventListeners( bIconified ? VclEventId::WindowMinimize : VclEventId::WindowNormalize ); +} + +bool Window::HasActiveChildFrame() const +{ + bool bRet = false; + vcl::Window *pFrameWin = ImplGetSVData()->maFrameData.mpFirstFrame; + while( pFrameWin ) + { + if( pFrameWin != mpWindowImpl->mpFrameWindow ) + { + bool bDecorated = false; + VclPtr< vcl::Window > pChildFrame = pFrameWin->ImplGetWindow(); + // #i15285# unfortunately WB_MOVEABLE is the same as WB_TABSTOP which can + // be removed for ToolBoxes to influence the keyboard accessibility + // thus WB_MOVEABLE is no indicator for decoration anymore + // but FloatingWindows carry this information in their TitleType... + // TODO: avoid duplicate WinBits !!! + if( pChildFrame && pChildFrame->ImplIsFloatingWindow() ) + bDecorated = static_cast(pChildFrame.get())->GetTitleType() != FloatWinTitleType::NONE; + if( bDecorated || (pFrameWin->mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) ) ) + if( pChildFrame && pChildFrame->IsVisible() && pChildFrame->IsActive() ) + { + if( ImplIsChild( pChildFrame, true ) ) + { + bRet = true; + break; + } + } + } + pFrameWin = pFrameWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + return bRet; +} + +LanguageType Window::GetInputLanguage() const +{ + return mpWindowImpl->mpFrame->GetInputLanguage(); +} + +void Window::EnableNativeWidget( bool bEnable ) +{ + static const char* pNoNWF = getenv( "SAL_NO_NWF" ); + if( pNoNWF && *pNoNWF ) + bEnable = false; + + if( bEnable != ImplGetWinData()->mbEnableNativeWidget ) + { + ImplGetWinData()->mbEnableNativeWidget = bEnable; + + // send datachanged event to allow for internal changes required for NWF + // like clipmode, transparency, etc. + DataChangedEvent aDCEvt( DataChangedEventType::SETTINGS, GetOutDev()->mxSettings.get(), AllSettingsFlags::STYLE ); + CompatDataChanged( aDCEvt ); + + // sometimes the borderwindow is queried, so keep it in sync + if( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->ImplGetWinData()->mbEnableNativeWidget = bEnable; + } + + // push down, useful for compound controls + VclPtr< vcl::Window > pChild = mpWindowImpl->mpFirstChild; + while( pChild ) + { + pChild->EnableNativeWidget( bEnable ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +bool Window::IsNativeWidgetEnabled() const +{ + return mpWindowImpl && ImplGetWinData()->mbEnableNativeWidget; +} + +Reference< css::rendering::XCanvas > WindowOutputDevice::ImplGetCanvas( bool bSpriteCanvas ) const +{ + // Feed any with operating system's window handle + + // common: first any is VCL pointer to window (for VCL canvas) + Sequence< Any > aArg{ + Any(reinterpret_cast(this)), + Any(css::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight )), + Any(mxOwnerWindow->mpWindowImpl->mbAlwaysOnTop), + Any(Reference< css::awt::XWindow >( + mxOwnerWindow->GetComponentInterface(), + UNO_QUERY )), + GetSystemGfxDataAny() + }; + + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + + // Create canvas instance with window handle + + static vcl::DeleteUnoReferenceOnDeinit xStaticCanvasFactory( + css::rendering::CanvasFactory::create( xContext ) ); + Reference xCanvasFactory(xStaticCanvasFactory.get()); + Reference< css::rendering::XCanvas > xCanvas; + + if(xCanvasFactory.is()) + { +#ifdef _WIN32 + // see #140456# - if we're running on a multiscreen setup, + // request special, multi-screen safe sprite canvas + // implementation (not DX5 canvas, as it cannot cope with + // surfaces spanning multiple displays). Note: canvas + // (without sprite) stays the same) + const sal_uInt32 nDisplay = static_cast< WinSalFrame* >( mxOwnerWindow->mpWindowImpl->mpFrame )->mnDisplay; + if( nDisplay >= Application::GetScreenCount() ) + { + xCanvas.set( xCanvasFactory->createInstanceWithArgumentsAndContext( + bSpriteCanvas ? + OUString( "com.sun.star.rendering.SpriteCanvas.MultiScreen" ) : + OUString( "com.sun.star.rendering.Canvas.MultiScreen" ), + aArg, + xContext ), + UNO_QUERY ); + + } + else +#endif + { + xCanvas.set( xCanvasFactory->createInstanceWithArgumentsAndContext( + bSpriteCanvas ? + OUString( "com.sun.star.rendering.SpriteCanvas" ) : + OUString( "com.sun.star.rendering.Canvas" ), + aArg, + xContext ), + UNO_QUERY ); + + } + } + + // no factory??? Empty reference, then. + return xCanvas; +} + +OUString Window::GetSurroundingText() const +{ + return OUString(); +} + +Selection Window::GetSurroundingTextSelection() const +{ + return Selection( 0, 0 ); +} + +namespace +{ + using namespace com::sun::star; + + uno::Reference lcl_GetxText(vcl::Window *pFocusWin) + { + uno::Reference xText; + try + { + uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible() ); + if (xAccessible.is()) + xText = FindFocusedEditableText(xAccessible->getAccessibleContext()); + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "vcl.gtk3", "Exception in getting input method surrounding text"); + } + return xText; + } +} + +// this is a rubbish implementation using a11y, ideally all subclasses implementing +// GetSurroundingText/GetSurroundingTextSelection should implement this and then this +// should be removed in favor of a stub that returns false +bool Window::DeleteSurroundingText(const Selection& rSelection) +{ + uno::Reference xText = lcl_GetxText(this); + if (xText.is()) + { + sal_Int32 nPosition = xText->getCaretPosition(); + // #i111768# range checking + sal_Int32 nDeletePos = rSelection.Min(); + sal_Int32 nDeleteEnd = rSelection.Max(); + if (nDeletePos < 0) + nDeletePos = 0; + if (nDeleteEnd < 0) + nDeleteEnd = 0; + if (nDeleteEnd > xText->getCharacterCount()) + nDeleteEnd = xText->getCharacterCount(); + + xText->deleteText(nDeletePos, nDeleteEnd); + //tdf91641 adjust cursor if deleted chars shift it forward (normal case) + if (nDeletePos < nPosition) + { + if (nDeleteEnd <= nPosition) + nPosition = nPosition - (nDeleteEnd - nDeletePos); + else + nPosition = nDeletePos; + + if (xText->getCharacterCount() >= nPosition) + xText->setCaretPosition( nPosition ); + } + return true; + } + + return false; +} + +bool WindowOutputDevice::UsePolyPolygonForComplexGradient() +{ + return meRasterOp != RasterOp::OverPaint; +} + +void Window::ApplySettings(vcl::RenderContext& /*rRenderContext*/) +{ +} + +const SystemEnvData* Window::GetSystemData() const +{ + + return mpWindowImpl->mpFrame ? mpWindowImpl->mpFrame->GetSystemData() : nullptr; +} + +bool Window::SupportsDoubleBuffering() const +{ + return mpWindowImpl->mpFrameData->mpBuffer; +} + +void Window::RequestDoubleBuffering(bool bRequest) +{ + if (bRequest) + { + mpWindowImpl->mpFrameData->mpBuffer = VclPtrInstance(); + // Make sure that the buffer size matches the frame size. + mpWindowImpl->mpFrameData->mpBuffer->SetOutputSizePixel(mpWindowImpl->mpFrameWindow->GetOutputSizePixel()); + } + else + mpWindowImpl->mpFrameData->mpBuffer.reset(); +} + +/* + * The rationale here is that we moved destructors to + * dispose and this altered a lot of code paths, that + * are better left unchanged for now. + */ +void Window::CompatGetFocus() +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + Window::GetFocus(); + else + GetFocus(); +} + +void Window::CompatLoseFocus() +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + Window::LoseFocus(); + else + LoseFocus(); +} + +void Window::CompatStateChanged( StateChangedType nStateChange ) +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + Window::StateChanged(nStateChange); + else + StateChanged(nStateChange); +} + +void Window::CompatDataChanged( const DataChangedEvent& rDCEvt ) +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + Window::DataChanged(rDCEvt); + else + DataChanged(rDCEvt); +} + +bool Window::CompatPreNotify( NotifyEvent& rNEvt ) +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + return Window::PreNotify( rNEvt ); + else + return PreNotify( rNEvt ); +} + +bool Window::CompatNotify( NotifyEvent& rNEvt ) +{ + if (!mpWindowImpl || mpWindowImpl->mbInDispose) + return Window::EventNotify( rNEvt ); + else + return EventNotify( rNEvt ); +} + +void Window::set_id(const OUString& rID) +{ + mpWindowImpl->maID = rID; +} + +const OUString& Window::get_id() const +{ + static OUString empty; + return mpWindowImpl ? mpWindowImpl->maID : empty; +} + +FactoryFunction Window::GetUITestFactory() const +{ + return WindowUIObject::create; +} + +WindowOutputDevice::WindowOutputDevice(vcl::Window& rOwnerWindow) : + ::OutputDevice(OUTDEV_WINDOW), + mxOwnerWindow(&rOwnerWindow) +{ + assert(mxOwnerWindow); +} + +WindowOutputDevice::~WindowOutputDevice() +{ + disposeOnce(); +} + +void WindowOutputDevice::dispose() +{ + assert((!mxOwnerWindow || mxOwnerWindow->isDisposed()) && "This belongs to the associated window and must be disposed after it"); + ::OutputDevice::dispose(); + // need to do this after OutputDevice::dispose so that the call to WindowOutputDevice::ReleaseGraphics + // can release the graphics properly + mxOwnerWindow.clear(); +} + +css::awt::DeviceInfo WindowOutputDevice::GetDeviceInfo() const +{ + css::awt::DeviceInfo aInfo = GetCommonDeviceInfo(mxOwnerWindow->GetSizePixel()); + mxOwnerWindow->GetBorder(aInfo.LeftInset, aInfo.TopInset, aInfo.RightInset, aInfo.BottomInset); + return aInfo; +} + + +} /* namespace vcl */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3