83b62f2f66
Change-Id: Ia5b0fd303f5a3b2c4c119f431517cc063070f4a4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176501 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
3993 lines
148 KiB
C++
3993 lines
148 KiB
C++
/* -*- 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 <sal/config.h>
|
|
|
|
#include <rtl/strbuf.hxx>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <sal/types.h>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
#include <vcl/salgtype.hxx>
|
|
#include <vcl/event.hxx>
|
|
#include <vcl/cursor.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/transfer.hxx>
|
|
#include <vcl/vclevent.hxx>
|
|
#include <vcl/window.hxx>
|
|
#include <vcl/syswin.hxx>
|
|
#include <vcl/dockwin.hxx>
|
|
#include <vcl/wall.hxx>
|
|
#include <vcl/toolkit/fixed.hxx>
|
|
#include <vcl/toolkit/button.hxx>
|
|
#include <vcl/taskpanelist.hxx>
|
|
#include <vcl/toolkit/unowrap.hxx>
|
|
#include <tools/lazydelete.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/sysdata.hxx>
|
|
#include <vcl/ptrstyle.hxx>
|
|
#include <vcl/IDialogRenderable.hxx>
|
|
|
|
#include <vcl/uitest/uiobject.hxx>
|
|
|
|
#include <ImplOutDevData.hxx>
|
|
#include <impfontcache.hxx>
|
|
#include <salframe.hxx>
|
|
#include <salobj.hxx>
|
|
#include <salinst.hxx>
|
|
#include <salgdi.hxx>
|
|
#include <svdata.hxx>
|
|
#include <window.h>
|
|
#include <toolbox.h>
|
|
#include <brdwin.hxx>
|
|
#include <helpwin.hxx>
|
|
#include <dndlistenercontainer.hxx>
|
|
#include <dndeventdispatcher.hxx>
|
|
|
|
#include <com/sun/star/accessibility/AccessibleRelation.hpp>
|
|
#include <com/sun/star/accessibility/XAccessible.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
|
|
#include <com/sun/star/awt/XVclWindowPeer.hpp>
|
|
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
|
|
#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
|
|
#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
|
|
#include <com/sun/star/rendering/CanvasFactory.hpp>
|
|
#include <com/sun/star/rendering/XSpriteCanvas.hpp>
|
|
#include <comphelper/configuration.hxx>
|
|
#include <comphelper/lok.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <tools/debug.hxx>
|
|
#include <tools/json_writer.hxx>
|
|
#include <boost/property_tree/ptree.hpp>
|
|
|
|
#include <cassert>
|
|
#include <typeinfo>
|
|
|
|
#ifdef _WIN32 // see #140456#
|
|
#include <win/salframe.h>
|
|
#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( !IsNativeFrame() && 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<vcl::Window> >& rList = ImplGetOwnerDrawList();
|
|
auto p = ::std::find( rList.begin(), rList.end(), VclPtr<vcl::Window>(this) );
|
|
if( p != rList.end() )
|
|
rList.erase( p );
|
|
}
|
|
|
|
// shutdown drag and drop
|
|
if( mpWindowImpl->mxDNDListenerContainer.is() )
|
|
mpWindowImpl->mxDNDListenerContainer->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(mpWindowImpl->mpFrameData->mxDropTargetListener);
|
|
}
|
|
|
|
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();
|
|
mpWindowImpl->mxAccessible.clear();
|
|
}
|
|
|
|
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<SystemWindow *>(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<SystemWindow *>(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<VclPtr<FixedText> > 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<OutputDevice> 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<vcl::Window>(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 ? mpWindowImpl->mxOutDev.get() : nullptr;
|
|
}
|
|
|
|
::OutputDevice* Window::GetOutDev()
|
|
{
|
|
return mpWindowImpl ? mpWindowImpl->mxOutDev.get() : nullptr;
|
|
}
|
|
|
|
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<vcl::WindowOutputDevice>::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;
|
|
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 = -32767;
|
|
mnLastMouseY = -32767;
|
|
mnBeforeLastMouseX = -32767;
|
|
mnBeforeLastMouseY = -32767;
|
|
mnFirstMouseX = -32767;
|
|
mnFirstMouseY = -32767;
|
|
mnLastMouseWinX = -32767;
|
|
mnLastMouseWinY = -32767;
|
|
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;
|
|
mnTouchPanPositionX = -1;
|
|
mnTouchPanPositionY = -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<vcl::WindowOutputDevice*>(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<vcl::WindowOutputDevice*>(this);
|
|
if ( mpNextGraphics )
|
|
mpNextGraphics->mpPrevGraphics = const_cast<vcl::WindowOutputDevice*>(this);
|
|
if ( !pSVData->maGDIData.mpLastWinGraphics )
|
|
pSVData->maGDIData.mpLastWinGraphics = const_cast<vcl::WindowOutputDevice*>(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<vcl::WindowOutputDevice*>(mpNextGraphics.get());
|
|
if ( mpNextGraphics )
|
|
mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
|
|
else
|
|
pSVData->maGDIData.mpLastWinGraphics = static_cast<vcl::WindowOutputDevice*>(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<ImplBorderWindow> pBorderWin( pParent, nStyle & (WB_BORDER | WB_DIALOGCONTROL | WB_NODIALOGCONTROL), nBorderTypeStyle );
|
|
static_cast<vcl::Window*>(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<ImplBorderWindow*>(this)->mbFloatWindow) || (nStyle & WB_SYSTEMFLOATWIN) ) ) ||
|
|
// 2. borderwindows of floaters with ownerdraw decoration
|
|
((GetType() == WindowType::BORDERWINDOW) && static_cast<ImplBorderWindow*>(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(
|
|
u"Could not create system window!"_ustr,
|
|
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 (!comphelper::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 (!comphelper::IsFuzzing())
|
|
{
|
|
const StyleSettings& rStyleSettings = mpWindowImpl->mxOutDev->moSettings->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<vcl::Window*>(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<const vcl::WindowOutputDevice&>(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()->moSettings->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,
|
|
bool bUseRenderContextDPI) const
|
|
{
|
|
Size aSize = rFont.GetFontSize();
|
|
|
|
if (aSize.Width())
|
|
{
|
|
aSize.setWidth( aSize.Width() *
|
|
( bUseRenderContextDPI ? rRenderContext.GetDPIX() : mpWindowImpl->mpFrameData->mnDPIX) );
|
|
aSize.AdjustWidth(72 / 2 );
|
|
aSize.setWidth( aSize.Width() / 72 );
|
|
}
|
|
aSize.setHeight( aSize.Height()
|
|
* ( bUseRenderContextDPI ? rRenderContext.GetDPIY() : mpWindowImpl->mpFrameData->mnDPIY) );
|
|
aSize.AdjustHeight(72/2 );
|
|
aSize.setHeight( aSize.Height() / 72 );
|
|
|
|
aSize = rRenderContext.PixelToLogic(aSize);
|
|
|
|
rFont.SetFontSize(aSize);
|
|
}
|
|
|
|
void Window::ImplLogicToPoint(vcl::RenderContext const & rRenderContext, vcl::Font& rFont) const
|
|
{
|
|
Size aSize = rFont.GetFontSize();
|
|
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<vcl::Region> pOverlapRegion;
|
|
std::unique_ptr<vcl::Region> 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( 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();
|
|
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 );
|
|
}
|
|
aNewContext.mpFont =
|
|
pFocusWin->GetOutDev()->mxFontCache->GetFontInstance(
|
|
pFocusWin->GetOutDev()->mxFontCollection.get(),
|
|
rFont, aSize, static_cast<float>(aSize.Height()) );
|
|
}
|
|
aNewContext.mnOptions = rInputContext.GetOptions();
|
|
pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext );
|
|
}
|
|
|
|
void Window::SetDumpAsPropertyTreeHdl(const Link<tools::JsonWriter&, void>& rLink)
|
|
{
|
|
if (mpWindowImpl) // may be called after dispose
|
|
{
|
|
mpWindowImpl->maDumpAsPropertyTreeHdl = rLink;
|
|
}
|
|
}
|
|
|
|
void Window::SetModalHierarchyHdl(const Link<bool, void>& 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 )
|
|
{
|
|
#ifndef _WIN32 // On Windows, dialogs react to accelerators without Alt (tdf#157649)
|
|
KeyCode cod = rKEvt.GetKeyCode ();
|
|
|
|
// do not respond to accelerators unless Alt or Ctrl is held
|
|
if (cod.GetCode () >= 0x200 && cod.GetCode () <= 0x219)
|
|
{
|
|
bool autoacc = ImplGetSVData()->maNWFData.mbAutoAccel;
|
|
if (autoacc && cod.GetModifier () != KEY_MOD2 && !(cod.GetModifier() & KEY_MOD1))
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
NotifyEvent aNEvt( NotifyEventType::KEYINPUT, this, &rKEvt );
|
|
if ( !CompatNotify( aNEvt ) )
|
|
mpWindowImpl->mbKeyInput = true;
|
|
}
|
|
|
|
void Window::KeyUp( const KeyEvent& rKEvt )
|
|
{
|
|
NotifyEvent aNEvt( NotifyEventType::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<vcl::Window> xWindow(this);
|
|
mpWindowImpl->mpLastFocusWindow->GrabFocus();
|
|
if( xWindow->isDisposed() )
|
|
return;
|
|
}
|
|
|
|
NotifyEvent aNEvt( NotifyEventType::GETFOCUS, this );
|
|
CompatNotify( aNEvt );
|
|
}
|
|
|
|
void Window::LoseFocus()
|
|
{
|
|
NotifyEvent aNEvt( NotifyEventType::LOSEFOCUS, this );
|
|
CompatNotify( aNEvt );
|
|
}
|
|
|
|
void Window::SetHelpHdl(const Link<vcl::Window&, bool>& 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( GetHelpId() );
|
|
if ( aStrHelpId.isEmpty() && ImplGetParent() )
|
|
ImplGetParent()->RequestHelp( rHEvt );
|
|
else
|
|
{
|
|
Help* pHelp = Application::GetHelp();
|
|
if ( pHelp )
|
|
{
|
|
if( !aStrHelpId.isEmpty() )
|
|
pHelp->Start( aStrHelpId, this );
|
|
else
|
|
pHelp->Start( u"" OOO_HELP_INDEX ""_ustr, this );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Window::Command( const CommandEvent& rCEvt )
|
|
{
|
|
CallEventListeners( VclEventId::WindowCommand, const_cast<CommandEvent *>(&rCEvt) );
|
|
|
|
NotifyEvent aNEvt( NotifyEventType::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<vcl::Window> 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<ImplBorderWindow*>(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<ImplBorderWindow*>(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<ImplBorderWindow*>(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<vcl::Window*>(this)->SetPointFont(const_cast<::OutputDevice&>(*GetOutDev()), rStyleSettings.GetTitleFont());
|
|
tools::Long nTitleWidth = GetTextWidth( GetText() );
|
|
const_cast<vcl::Window*>(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<ExtTextInputAttr[]> 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<vcl::Window *>& 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,
|
|
bool bUseRenderContextDPI)
|
|
{
|
|
vcl::Font aFont = rFont;
|
|
ImplPointToLogic(rRenderContext, aFont, bUseRenderContextDPI);
|
|
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<vcl::Window> 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())
|
|
{
|
|
if (!(nFlags & ShowFlags::NoActivate))
|
|
{
|
|
ImplStartToTop((nFlags & ShowFlags::ForegroundTask) ? ToTopFlags::ForegroundTask
|
|
: ToTopFlags::NONE);
|
|
ImplFocusToTop(ToTopFlags::NONE, false);
|
|
|
|
if (!(nFlags & ShowFlags::ForegroundTask))
|
|
{
|
|
// Inform user about window if we did not popup it at foreground
|
|
FlashWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 );
|
|
}
|
|
|
|
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<vcl::Window> xWindow( const_cast<Window*>(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<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow )
|
|
static_cast<ImplBorderWindow*>(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<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow )
|
|
static_cast<ImplBorderWindow*>(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<vcl::Window> >& 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<vcl::Window> 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<vcl::Window> pParent = GetParent();
|
|
VclPtr<vcl::Window> 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->GetWidth())
|
|
{
|
|
// 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.width();
|
|
if( !myWidth )
|
|
myWidth = nWidth;
|
|
nFlags |= PosSizeFlags::X;
|
|
nSysFlags |= SAL_FRAME_POSSIZE_X;
|
|
nX = aParentSysGeometry.x() - aSysGeometry.leftDecoration() + aParentSysGeometry.width()
|
|
- myWidth - 1 - aSysGeometry.x();
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
AbsoluteScreenPixelRectangle Window::GetDesktopRectPixel() const
|
|
{
|
|
AbsoluteScreenPixelRectangle 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() const
|
|
{
|
|
// revert mnOutOffX changes that were potentially made in ImplPosSizeWindow
|
|
tools::Long offx = GetOutDev()->mnOutOffX;
|
|
const 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 = 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 = ImplGetUnmirroredOutOffX();
|
|
return Point( rPos.X()-offx, rPos.Y() - GetOutDev()->mnOutOffY );
|
|
}
|
|
|
|
AbsoluteScreenPixelPoint Window::OutputToAbsoluteScreenPixel( const Point& rPos ) const
|
|
{
|
|
// relative to the screen
|
|
Point p = OutputToScreenPixel( rPos );
|
|
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
|
|
p.AdjustX(g.x() );
|
|
p.AdjustY(g.y() );
|
|
return AbsoluteScreenPixelPoint(p);
|
|
}
|
|
|
|
Point Window::AbsoluteScreenToOutputPixel( const AbsoluteScreenPixelPoint& rPos ) const
|
|
{
|
|
// relative to the screen
|
|
Point p = ScreenToOutputPixel( Point(rPos) );
|
|
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
|
|
p.AdjustX( -(g.x()) );
|
|
p.AdjustY( -(g.y()) );
|
|
return p;
|
|
}
|
|
|
|
AbsoluteScreenPixelRectangle 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.x()+g.width()-p1.X() );
|
|
p1.AdjustY(g.y() );
|
|
|
|
Point p2 = rRect.BottomLeft();
|
|
p2 = OutputToScreenPixel(p2);
|
|
p2.setX( g.x()+g.width()-p2.X() );
|
|
p2.AdjustY(g.y() );
|
|
|
|
return AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint(p1), AbsoluteScreenPixelPoint(p2) );
|
|
}
|
|
|
|
tools::Rectangle Window::ImplUnmirroredAbsoluteScreenToOutputPixel( const AbsoluteScreenPixelRectangle &rRect ) const
|
|
{
|
|
// undo ImplOutputToUnmirroredAbsoluteScreenPixel
|
|
SalFrameGeometry g = mpWindowImpl->mpFrame->GetUnmirroredGeometry();
|
|
|
|
Point p1( rRect.TopRight() );
|
|
p1.AdjustY(-g.y() );
|
|
p1.setX( g.x()+g.width()-p1.X() );
|
|
p1 = ScreenToOutputPixel(p1);
|
|
|
|
Point p2( rRect.BottomLeft() );
|
|
p2.AdjustY(-g.y());
|
|
p2.setX( g.x()+g.width()-p2.X() );
|
|
p2 = ScreenToOutputPixel(p2);
|
|
|
|
return tools::Rectangle( p1, p2 );
|
|
}
|
|
|
|
|
|
// with decoration
|
|
tools::Rectangle Window::GetWindowExtentsRelative(const vcl::Window & rRelativeWindow) const
|
|
{
|
|
AbsoluteScreenPixelRectangle aRect = GetWindowExtentsAbsolute();
|
|
// #106399# express coordinates relative to borderwindow
|
|
const vcl::Window *pRelWin = rRelativeWindow.mpWindowImpl->mpBorderWindow ? rRelativeWindow.mpWindowImpl->mpBorderWindow.get() : &rRelativeWindow;
|
|
return tools::Rectangle(
|
|
pRelWin->AbsoluteScreenToOutputPixel( aRect.GetPos() ),
|
|
aRect.GetSize() );
|
|
}
|
|
|
|
// with decoration
|
|
AbsoluteScreenPixelRectangle Window::GetWindowExtentsAbsolute() const
|
|
{
|
|
// 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;
|
|
|
|
AbsoluteScreenPixelPoint aPos( pWin->OutputToAbsoluteScreenPixel( Point(0,0) ) );
|
|
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) )
|
|
{
|
|
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
|
|
aPos.AdjustX( -sal_Int32(g.leftDecoration()) );
|
|
aPos.AdjustY( -sal_Int32(g.topDecoration()) );
|
|
aSize.AdjustWidth(g.leftDecoration() + g.rightDecoration() );
|
|
aSize.AdjustHeight(g.topDecoration() + g.bottomDecoration() );
|
|
}
|
|
return AbsoluteScreenPixelRectangle( 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<vcl::Window> Window::GetFocusedWindow() const
|
|
{
|
|
if (mpWindowImpl && mpWindowImpl->mpFrameData)
|
|
return mpWindowImpl->mpFrameData->mpFocusWin;
|
|
else
|
|
return VclPtr<vcl::Window>();
|
|
}
|
|
|
|
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<const ToolBox*>(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
|
|
{
|
|
const OUString& rStrHelpId(GetHelpId());
|
|
const bool bStrHelpId = !rStrHelpId.isEmpty();
|
|
|
|
if (mpWindowImpl->mbHelpTextDynamic && bStrHelpId)
|
|
{
|
|
static const char* pEnv = getenv( "HELP_DEBUG" );
|
|
if( pEnv && *pEnv )
|
|
{
|
|
mpWindowImpl->maHelpText = mpWindowImpl->maHelpText + "\n------------------\n" + rStrHelpId;
|
|
}
|
|
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::XVclWindowPeer > 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::XVclWindowPeer > 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::XVclWindowPeer > const & xIFace )
|
|
{
|
|
UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
|
|
SAL_WARN_IF( !pWrapper, "vcl.window", "SetComponentInterface: No Wrapper!" );
|
|
if ( pWrapper )
|
|
pWrapper->SetWindowInterface( this, xIFace );
|
|
}
|
|
|
|
typedef std::map<vcl::LOKWindowId, VclPtr<vcl::Window>> 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);
|
|
}
|
|
|
|
mpWindowImpl->mpLOKNotifier = pNotifier;
|
|
}
|
|
|
|
VclPtr<Window> Window::FindLOKWindow(vcl::LOKWindowId nWindowId)
|
|
{
|
|
const auto it = GetLOKWindowsMap().find(nWindowId);
|
|
if (it != GetLOKWindowsMap().end())
|
|
return it->second;
|
|
|
|
return VclPtr<Window>();
|
|
}
|
|
|
|
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<vcl::Window> Window::GetParentWithLOKNotifier()
|
|
{
|
|
VclPtr<vcl::Window> pWindow(this);
|
|
|
|
while (pWindow && !pWindow->GetLOKNotifier())
|
|
pWindow = pWindow->GetParent();
|
|
|
|
return pWindow;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
std::string_view 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";
|
|
case WindowType::PROGRESSBAR: return "progressbar";
|
|
case WindowType::LINK_BUTTON: return "linkbutton";
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
vcl::Window* pAccLabelFor = getAccessibleRelationLabelFor();
|
|
if (pAccLabelFor)
|
|
rJsonWriter.put("labelFor", pAccLabelFor->get_id());
|
|
|
|
vcl::Window* pAccLabelledBy = GetAccessibleRelationLabeledBy();
|
|
if (pAccLabelledBy)
|
|
rJsonWriter.put("labelledBy", pAccLabelledBy->get_id());
|
|
|
|
if(!pAccLabelFor && !pAccLabelledBy)
|
|
{
|
|
OUString sAccName = GetAccessibleName();
|
|
OUString sAccDesc = GetAccessibleDescription();
|
|
|
|
if (!sAccName.isEmpty() || !sAccDesc.isEmpty())
|
|
{
|
|
auto aAria = rJsonWriter.startNode("aria");
|
|
if (!sAccName.isEmpty())
|
|
rJsonWriter.put("label", sAccName);
|
|
if (!sAccDesc.isEmpty())
|
|
rJsonWriter.put("description", sAccDesc);
|
|
}
|
|
}
|
|
|
|
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<vcl::Window> 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<vcl::Window> 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<XClipboard> const & xClipboard)
|
|
{
|
|
if (mpWindowImpl->mpFrameData)
|
|
mpWindowImpl->mpFrameData->mxClipboard = xClipboard;
|
|
}
|
|
|
|
Reference< XClipboard > Window::GetClipboard()
|
|
{
|
|
if (!mpWindowImpl->mpFrameData)
|
|
return static_cast<XClipboard*>(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->GetWidth() - 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<FloatingWindow*>(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()->moSettings, 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<sal_Int64>(this)),
|
|
Any(css::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight )),
|
|
Any(mxOwnerWindow->mpWindowImpl->mbAlwaysOnTop),
|
|
Any(Reference< css::awt::XWindow >(
|
|
mxOwnerWindow->GetComponentInterface(),
|
|
UNO_QUERY )),
|
|
GetSystemGfxDataAny()
|
|
};
|
|
|
|
const Reference< XComponentContext >& xContext = comphelper::getProcessComponentContext();
|
|
|
|
// Create canvas instance with window handle
|
|
|
|
static tools::DeleteUnoReferenceOnDeinit<XMultiComponentFactory> xStaticCanvasFactory(
|
|
css::rendering::CanvasFactory::create( xContext ) );
|
|
Reference<XMultiComponentFactory> 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 ?
|
|
u"com.sun.star.rendering.SpriteCanvas"_ustr :
|
|
u"com.sun.star.rendering.Canvas"_ustr,
|
|
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<accessibility::XAccessibleEditableText> lcl_GetxText(vcl::Window *pFocusWin)
|
|
{
|
|
uno::Reference<accessibility::XAccessibleEditableText> 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<accessibility::XAccessibleEditableText> 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<VirtualDevice>();
|
|
// 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: */
|