Files
libreoffice/vcl/source/window/window.cxx
Tomaž Vajngerl 69b6ab1f8d tdf#100164 change scaling unit to precentage for *.5x factors
Currently we support DPI scaling by a integer factor. This commit
changes that to percentage so we can have scaling factors like
1.5x or 1.25x. This is useful with 2.7k monitors that are in
between standard DPI and HiDPI. Thresholding was adjusted to scale
to 1.5x when DPI is between 120 and 168 DPI.

The old method GetDPIScaleFactor has been changed to return a
float value insted of int. Sometimes it is however more accurate
to use GetDPIScalePercentage which was added in this commit.

Change-Id: Iaecee793ff3d5084d00adeebbcf5d7368c580882
Reviewed-on: https://gerrit.libreoffice.org/30379
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
2016-10-29 21:47:41 +00:00

3749 lines
137 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 <config_features.h>
#include <rtl/strbuf.hxx>
#include <tools/rc.h>
#include <sal/types.h>
#include <vcl/salgtype.hxx>
#include <vcl/event.hxx>
#include <vcl/help.hxx>
#include <vcl/cursor.hxx>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
#include <vcl/syswin.hxx>
#include <vcl/syschild.hxx>
#include <vcl/dockwin.hxx>
#include <vcl/wall.hxx>
#include <vcl/fixed.hxx>
#include <vcl/gradient.hxx>
#include <vcl/button.hxx>
#include <vcl/taskpanelist.hxx>
#include <vcl/dialog.hxx>
#include <vcl/unowrap.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/lazydelete.hxx>
#include <vcl/virdev.hxx>
#include <vcl/settings.hxx>
#include <vcl/sysdata.hxx>
#include <vcl/uitest/uiobject.hxx>
#include <vcl/uitest/uitest.hxx>
#include <salframe.hxx>
#include <salobj.hxx>
#include <salinst.hxx>
#include <salgdi.hxx>
#include <svdata.hxx>
#include <window.h>
#include <toolbox.h>
#include <outdev.h>
#include <brdwin.hxx>
#include <helpwin.hxx>
#include "dndlistenercontainer.hxx"
#include <com/sun/star/awt/XDisplayConnection.hpp>
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
#include <com/sun/star/rendering/CanvasFactory.hpp>
#include <com/sun/star/rendering/XSpriteCanvas.hpp>
#include <comphelper/processfactory.hxx>
#include <unotools/configmgr.hxx>
#include <cassert>
#include <set>
#include <typeinfo>
#ifdef _WIN32 // see #140456#
#include <win/salframe.h>
#endif
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( nType ))
{
meOutDevType = OUTDEV_WINDOW;
// true: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active
mbEnableRTL = AllSettings::GetLayoutRTL();
}
Window::Window( vcl::Window* pParent, WinBits nStyle ) :
mpWindowImpl(new WindowImpl( WINDOW_WINDOW ))
{
meOutDevType = OUTDEV_WINDOW;
// true: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active
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() == WINDOW_BORDERWINDOW ) {
pTempWin = pTempWin->GetWindow( GetWindowType::FirstChild );
}
// check if pTempWin is not null, otherwise use the
// original address
if ( pTempWin ) {
pWindow = pTempWin;
}
OStringBuffer aErrorString;
aErrorString.append(' ');
aErrorString.append(typeid( *pWindow ).name());
aErrorString.append("(");
aErrorString.append(
OUStringToOString(
pWindow->GetText(),
RTL_TEXTENCODING_UTF8
)
);
aErrorString.append(")");
return aErrorString.makeStringAndClear();
}
}
#endif
bool Window::IsDisposed() const
{
return !mpWindowImpl;
}
void Window::dispose()
{
assert( mpWindowImpl );
assert( !mpWindowImpl->mbInDispose ); // should only be called from disposeOnce()
assert( (!mpWindowImpl->mpParent ||
!mpWindowImpl->mpParent->IsDisposed()) &&
"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.
Reference< css::rendering::XCanvas > xCanvas( mpWindowImpl->mxCanvas );
if( xCanvas.is() )
{
Reference < XComponent > xCanvasComponent( xCanvas, UNO_QUERY );
if( xCanvasComponent.is() )
xCanvasComponent->dispose();
}
mpWindowImpl->mbInDispose = true;
CallEventListeners( VCLEVENT_OBJECT_DYING );
// do not send child events for frames that were registered as native frames
if( !ImplIsAccessibleNativeFrame() && mpWindowImpl->mbReallyVisible )
if ( ImplIsAccessibleCandidate() && GetAccessibleParentWindow() )
GetAccessibleParentWindow()->CallEventListeners( VCLEVENT_WINDOW_CHILDDESTROYED, 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
Reference < XComponent > xDnDComponent( mpWindowImpl->mxDNDListenerContainer, UNO_QUERY );
if( xDnDComponent.is() )
xDnDComponent->dispose();
if( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData )
{
try
{
// deregister drop target listener
if( mpWindowImpl->mpFrameData->mxDropTargetListener.is() )
{
Reference< XDragGestureRecognizer > xDragGestureRecognizer =
Reference< XDragGestureRecognizer > (mpWindowImpl->mpFrameData->mxDragSource, UNO_QUERY);
if( xDragGestureRecognizer.is() )
{
xDragGestureRecognizer->removeDragGestureListener(
Reference< XDragGestureListener > (mpWindowImpl->mpFrameData->mxDropTargetListener, UNO_QUERY));
}
mpWindowImpl->mpFrameData->mxDropTarget->removeDropTargetListener( mpWindowImpl->mpFrameData->mxDropTargetListener );
mpWindowImpl->mpFrameData->mxDropTargetListener.clear();
}
// shutdown drag and drop for this frame window
Reference< XComponent > xComponent( mpWindowImpl->mpFrameData->mxDropTarget, UNO_QUERY );
// DNDEventDispatcher does not hold a reference of the DropTarget,
// so it's ok if it does not support XComponent
if( xComponent.is() )
xComponent->dispose();
}
catch (const Exception&)
{
// can be safely ignored here.
}
}
UnoWrapperBase* pWrapper = Application::GetUnoWrapper( false );
if ( pWrapper )
pWrapper->WindowDestroyed( this );
// MT: Must be called after WindowDestroyed!
// Otherwise, if the accessible is a VCLXWindow, it will try to destroy this window again!
// But accessibility implementations from applications need this dispose.
if ( mpWindowImpl->mxAccessible.is() )
{
Reference< XComponent> xC( mpWindowImpl->mxAccessible, UNO_QUERY );
if ( xC.is() )
xC->dispose();
}
ImplSVData* pSVData = ImplGetSVData();
if ( pSVData->maHelpData.mpHelpWin && (pSVData->maHelpData.mpHelpWin->GetParent() == this) )
ImplDestroyHelpWindow( true );
SAL_WARN_IF( pSVData->maWinData.mpTrackWin.get() == this, "vcl",
"Window::~Window(): Window is in TrackingMode" );
SAL_WARN_IF(IsMouseCaptured(), "vcl",
"Window::~Window(): Window has the mouse captured");
// due to old compatibility
if ( pSVData->maWinData.mpTrackWin == this )
EndTracking();
if (IsMouseCaptured())
ReleaseMouse();
#if OSL_DEBUG_LEVEL > 0
if ( true ) // always perform these tests in debug builds
{
OStringBuffer aErrorStr;
bool bError = false;
vcl::Window* pTempWin;
if ( mpWindowImpl->mpFirstChild )
{
OStringBuffer aTempStr("Window (");
aTempStr.append(lcl_createWindowInfo(this));
aTempStr.append(") 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.makeStringAndClear(), RTL_TEXTENCODING_UTF8)); // abort in debug builds, this must be fixed!
}
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 )
{
OStringBuffer aTempStr;
aTempStr.append("Window (");
aTempStr.append(lcl_createWindowInfo(this));
aTempStr.append(") with live SystemWindows destroyed: ");
aTempStr.append(aErrorStr.toString());
OSL_FAIL(aTempStr.getStr());
// abort in debug builds, must be fixed!
Application::Abort(OStringToOUString(
aTempStr.makeStringAndClear(), RTL_TEXTENCODING_UTF8));
}
}
bError = false;
pTempWin = pSVData->maWinData.mpFirstFrame;
while ( pTempWin )
{
if ( ImplIsRealParentPath( pTempWin ) )
{
bError = true;
aErrorStr.append(lcl_createWindowInfo(pTempWin));
}
pTempWin = pTempWin->mpWindowImpl->mpFrameData->mpNextFrame;
}
if ( bError )
{
OStringBuffer aTempStr( "Window (" );
aTempStr.append(lcl_createWindowInfo(this));
aTempStr.append(") with live SystemWindows destroyed: ");
aTempStr.append(aErrorStr.toString());
OSL_FAIL( aTempStr.getStr() );
Application::Abort(OStringToOUString(aTempStr.makeStringAndClear(), RTL_TEXTENCODING_UTF8)); // abort in debug builds, this must be fixed!
}
if ( mpWindowImpl->mpFirstOverlap )
{
OStringBuffer aTempStr("Window (");
aTempStr.append(lcl_createWindowInfo(this));
aTempStr.append(") 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.makeStringAndClear(), RTL_TEXTENCODING_UTF8)); // abort in debug builds, this must be fixed!
}
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 ) )
{
OStringBuffer aTempStr("Window (");
aTempStr.append(lcl_createWindowInfo(this));
aTempStr.append(") still in TaskPanelList!");
OSL_FAIL( aTempStr.getStr() );
Application::Abort(OStringToOUString(aTempStr.makeStringAndClear(), RTL_TEXTENCODING_UTF8)); // abort in debug builds, this must be fixed!
}
}
#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
{
OStringBuffer aTempStr("Window (");
aTempStr.append(OUStringToOString(GetText(), RTL_TEXTENCODING_UTF8));
aTempStr.append(") not found in TaskPanelList!");
OSL_FAIL( aTempStr.getStr() );
}
}
// remove from size-group if necessary
remove_from_all_size_groups();
// clear mnemonic labels
std::vector<VclPtr<FixedText> > aMnemonicLabels(list_mnemonic_labels());
for (auto aI = aMnemonicLabels.begin(); aI != aMnemonicLabels.end(); ++aI)
{
remove_mnemonic_label(*aI);
}
// hide window in order to trigger the Paint-Handling
Hide();
// announce the window is to be destroyed
{
NotifyEvent aNEvt( MouseNotifyEvent::DESTROY, this );
CompatNotify( aNEvt );
}
// EndExtTextInputMode
if ( pSVData->maWinData.mpExtTextInputWin == this )
{
EndExtTextInput();
if ( pSVData->maWinData.mpExtTextInputWin == this )
pSVData->maWinData.mpExtTextInputWin = nullptr;
}
// check if the focus window is our child
bool bHasFocussedChild = false;
if( pSVData->maWinData.mpFocusWin && ImplIsRealParentPath( pSVData->maWinData.mpFocusWin ) )
{
// #122232#, this must not happen and is an application bug ! but we try some cleanup to hopefully avoid crashes, see below
bHasFocussedChild = true;
#if OSL_DEBUG_LEVEL > 0
OStringBuffer aTempStr("Window (");
aTempStr.append(OUStringToOString(GetText(),
RTL_TEXTENCODING_UTF8)).
append(") with focussed child window destroyed ! THIS WILL LEAD TO CRASHES AND MUST BE FIXED !");
OSL_FAIL( aTempStr.getStr() );
Application::Abort(OStringToOUString(aTempStr.makeStringAndClear(), RTL_TEXTENCODING_UTF8 )); // abort in debug build version, this must be fixed!
#endif
}
// if we get focus pass focus to another window
vcl::Window* pOverlapWindow = ImplGetFirstOverlapWindow();
if ( pSVData->maWinData.mpFocusWin == this
|| bHasFocussedChild ) // #122232#, see above, try some cleanup
{
if ( mpWindowImpl->mbFrame )
{
pSVData->maWinData.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->maWinData.mpFocusWin == this )
{
pSVData->maWinData.mpFocusWin = nullptr;
pOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
}
}
}
if ( pOverlapWindow != nullptr &&
pOverlapWindow->mpWindowImpl->mpLastFocusWindow == this )
pOverlapWindow->mpWindowImpl->mpLastFocusWindow = nullptr;
// reset hint for DefModalDialogParent
if( pSVData->maWinData.mpActiveApplicationFrame == this )
pSVData->maWinData.mpActiveApplicationFrame = nullptr;
// reset hint of what was the last wheeled window
if( pSVData->maWinData.mpLastWheelWindow == this )
pSVData->maWinData.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->maWinData.mpLastDeacWin == this )
pSVData->maWinData.mpLastDeacWin = nullptr;
if ( 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
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: inconsistency in top window chain!" );
if ( myPos != pParentWinData->maTopWindowChildren.end() )
pParentWinData->maTopWindowChildren.erase( myPos );
}
}
delete mpWindowImpl->mpWinData;
// remove BorderWindow or Frame window data
mpWindowImpl->mpBorderWindow.disposeAndClear();
if ( mpWindowImpl->mbFrame )
{
if ( pSVData->maWinData.mpFirstFrame == this )
pSVData->maWinData.mpFirstFrame = mpWindowImpl->mpFrameData->mpNextFrame;
else
{
vcl::Window* pSysWin = pSVData->maWinData.mpFirstFrame;
while ( pSysWin->mpWindowImpl->mpFrameData->mpNextFrame.get() != this )
pSysWin = pSysWin->mpWindowImpl->mpFrameData->mpNextFrame;
assert (mpWindowImpl->mpFrameData->mpNextFrame.get() != pSysWin);
pSysWin->mpWindowImpl->mpFrameData->mpNextFrame = mpWindowImpl->mpFrameData->mpNextFrame;
}
mpWindowImpl->mpFrame->SetCallback( nullptr, nullptr );
pSVData->mpDefInst->DestroyFrame( mpWindowImpl->mpFrame );
assert (mpWindowImpl->mpFrameData->mnFocusId == nullptr);
assert (mpWindowImpl->mpFrameData->mnMouseMoveId == nullptr);
delete mpWindowImpl->mpFrameData;
}
// should be the last statements
mpWindowImpl.reset();
OutputDevice::dispose();
}
Window::~Window()
{
// FIXME: we should kill all LazyDeletor usage.
vcl::LazyDeletor::Undelete( this );
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 this;
}
::OutputDevice* Window::GetOutDev()
{
return this;
}
} /* namespace vcl */
WindowImpl::WindowImpl( WindowType nType )
{
maZoom = Fraction( 1, 1 );
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
mpControlFont = nullptr; // font properties
mpVCLXWindow = nullptr;
mpAccessibleInfos = nullptr;
maControlForeground = Color( COL_TRANSPARENT ); // no foreground set
maControlBackground = Color( 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 = 0; // extended style (init in ImplInitWindow)
mnPrevExtendedStyle = 0; // prevstyle (set in SetExtendedStyle)
mnType = nType; // type
mnGetFocusFlags = GetFocusFlags::NONE; // Flags fuer GetFocus()-Aufruf
mnWaitCount = 0; // Wait-Count (>1 == Warte-MousePointer)
mnPaintFlags = 0; // 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
mnLockCount = 0; // LockCount
meAlwaysInputMode = AlwaysInputNone; // neither AlwaysEnableInput nor AlwaysDisableInput 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 a 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
mbMouseMove = false; // true: BaseMouseMove 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
mbCallHandlersDuringInputDisabled = false; // true: call event handlers even if input is disabled
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
}
WindowImpl::~WindowImpl()
{
delete mpChildClipRegion;
delete mpAccessibleInfos;
delete mpControlFont;
}
ImplWinData::ImplWinData() :
mpExtOldText(nullptr),
mpExtOldAttrAry(nullptr),
mpCursorRect(nullptr),
mnCursorExtWidth(0),
mbVertical(false),
mpCompositionCharRects(nullptr),
mnCompositionCharRects(0),
mpFocusRect(nullptr),
mpTrackRect(nullptr),
mnTrackFlags(ShowTrackFlags::NONE),
mnIsTopWindow((sal_uInt16) ~0), // not initialized yet, 0/1 will indicate TopWindow (see IsTopWindow())
mbMouseOver(false),
mbEnableNativeWidget(false)
{
}
ImplWinData::~ImplWinData()
{
delete mpExtOldText;
delete mpExtOldAttrAry;
delete mpCursorRect;
delete[] mpCompositionCharRects;
delete mpFocusRect;
delete mpTrackRect;
}
namespace vcl {
bool Window::AcquireGraphics() const
{
DBG_TESTSOLARMUTEX();
if ( mpGraphics )
return true;
mbInitLineColor = true;
mbInitFillColor = true;
mbInitFont = true;
mbInitTextColor = true;
mbInitClipRegion = true;
ImplSVData* pSVData = ImplGetSVData();
mpGraphics = mpWindowImpl->mpFrame->AcquireGraphics();
// try harder if no wingraphics was available directly
if ( !mpGraphics )
{
// find another output device in the same frame
OutputDevice* pReleaseOutDev = pSVData->maGDIData.mpLastWinGraphics;
while ( pReleaseOutDev )
{
if ( static_cast<vcl::Window*>(pReleaseOutDev)->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame )
break;
pReleaseOutDev = pReleaseOutDev->mpPrevGraphics;
}
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 = mpWindowImpl->mpFrame->AcquireGraphics();
}
}
}
// update global LRU list of wingraphics
if ( mpGraphics )
{
mpNextGraphics = pSVData->maGDIData.mpFirstWinGraphics;
pSVData->maGDIData.mpFirstWinGraphics = const_cast<vcl::Window*>(this);
if ( mpNextGraphics )
mpNextGraphics->mpPrevGraphics = const_cast<vcl::Window*>(this);
if ( !pSVData->maGDIData.mpLastWinGraphics )
pSVData->maGDIData.mpLastWinGraphics = const_cast<vcl::Window*>(this);
}
if ( mpGraphics )
{
mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp) );
mpGraphics->setAntiAliasB2DDraw(bool(mnAntialiasing & AntialiasingFlags::EnableB2dDraw));
}
return mpGraphics != nullptr;
}
void Window::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 = this;
if ( bRelease )
pWindow->mpWindowImpl->mpFrame->ReleaseGraphics( mpGraphics );
// remove from global LRU list of window graphics
if ( mpPrevGraphics )
mpPrevGraphics->mpNextGraphics = mpNextGraphics;
else
pSVData->maGDIData.mpFirstWinGraphics = mpNextGraphics;
if ( mpNextGraphics )
mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
else
pSVData->maGDIData.mpLastWinGraphics = mpPrevGraphics;
mpGraphics = nullptr;
mpPrevGraphics = nullptr;
mpNextGraphics = nullptr;
}
static sal_Int32 CountDPIScaleFactor(sal_Int32 nDPI)
{
sal_Int32 nResult = 100;
#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 hi-dpi to greater than 168
if (nDPI > 216) // 96 * 2 + 96 / 4
nResult = 250;
else if (nDPI > 168) // 96 * 2 - 96 / 4
nResult = 200;
else if (nDPI > 120) // 96 * 1.5 - 96 / 4
nResult = 150;
#else
(void)nDPI;
#endif
return nResult;
}
void Window::ImplInit( vcl::Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData )
{
SAL_WARN_IF( !mpWindowImpl->mbFrame && !pParent && GetType() != WINDOW_FIXEDIMAGE, "vcl",
"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 )
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() == WINDOW_BORDERWINDOW) && static_cast<ImplBorderWindow*>(this)->mbFloatWindow) || (nStyle & WB_SYSTEMFLOATWIN) ) ) ||
// 2. borderwindows of floaters with ownerdraw decoration
( ((GetType() == WINDOW_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 WINDOW_DIALOG:
case WINDOW_TABDIALOG:
case WINDOW_MODALDIALOG:
case WINDOW_MODELESSDIALOG:
case WINDOW_MESSBOX:
case WINDOW_INFOBOX:
case WINDOW_WARNINGBOX:
case WINDOW_ERRORBOX:
case WINDOW_QUERYBOX:
nFrameStyle |= SalFrameStyleFlags::DIALOG;
break;
default:
break;
}
SalFrame* pParentFrame = nullptr;
if ( pParent )
pParentFrame = pParent->mpWindowImpl->mpFrame;
SalFrame* pFrame;
if ( pSystemParentData )
pFrame = pSVData->mpDefInst->CreateChildFrame( pSystemParentData, nFrameStyle | SalFrameStyleFlags::PLUG );
else
pFrame = pSVData->mpDefInst->CreateFrame( pParentFrame, nFrameStyle );
if ( !pFrame )
{
// do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
throw RuntimeException(
"Could not create system window!",
Reference< XInterface >() );
}
pFrame->SetCallback( this, ImplWindowFrameProc );
// set window frame data
mpWindowImpl->mpFrameData = new ImplFrameData;
mpWindowImpl->mpFrame = pFrame;
mpWindowImpl->mpFrameWindow = this;
mpWindowImpl->mpOverlapWindow = this;
// set frame data
assert (pSVData->maWinData.mpFirstFrame.get() != this);
mpWindowImpl->mpFrameData->mpNextFrame = pSVData->maWinData.mpFirstFrame;
pSVData->maWinData.mpFirstFrame = this;
mpWindowImpl->mpFrameData->mpFirstOverlap = nullptr;
mpWindowImpl->mpFrameData->mpFocusWin = nullptr;
mpWindowImpl->mpFrameData->mpMouseMoveWin = nullptr;
mpWindowImpl->mpFrameData->mpMouseDownWin = nullptr;
mpWindowImpl->mpFrameData->mpFontCollection = pSVData->maGDIData.mpScreenFontList;
mpWindowImpl->mpFrameData->mpFontCache = pSVData->maGDIData.mpScreenFontCache;
mpWindowImpl->mpFrameData->mnFocusId = nullptr;
mpWindowImpl->mpFrameData->mnMouseMoveId = nullptr;
mpWindowImpl->mpFrameData->mnLastMouseX = -1;
mpWindowImpl->mpFrameData->mnLastMouseY = -1;
mpWindowImpl->mpFrameData->mnBeforeLastMouseX = -1;
mpWindowImpl->mpFrameData->mnBeforeLastMouseY = -1;
mpWindowImpl->mpFrameData->mnFirstMouseX = -1;
mpWindowImpl->mpFrameData->mnFirstMouseY = -1;
mpWindowImpl->mpFrameData->mnLastMouseWinX = -1;
mpWindowImpl->mpFrameData->mnLastMouseWinY = -1;
mpWindowImpl->mpFrameData->mnModalMode = 0;
mpWindowImpl->mpFrameData->mnMouseDownTime = 0;
mpWindowImpl->mpFrameData->mnClickCount = 0;
mpWindowImpl->mpFrameData->mnFirstMouseCode = 0;
mpWindowImpl->mpFrameData->mnMouseCode = 0;
mpWindowImpl->mpFrameData->mnMouseMode = MouseEventModifiers::NONE;
mpWindowImpl->mpFrameData->meMapUnit = MapUnit::MapPixel;
mpWindowImpl->mpFrameData->mbHasFocus = false;
mpWindowImpl->mpFrameData->mbInMouseMove = false;
mpWindowImpl->mpFrameData->mbMouseIn = false;
mpWindowImpl->mpFrameData->mbStartDragCalled = false;
mpWindowImpl->mpFrameData->mbNeedSysWindow = false;
mpWindowImpl->mpFrameData->mbMinimized = false;
mpWindowImpl->mpFrameData->mbStartFocusState = false;
mpWindowImpl->mpFrameData->mbInSysObjFocusHdl = false;
mpWindowImpl->mpFrameData->mbInSysObjToTopHdl = false;
mpWindowImpl->mpFrameData->mbSysObjFocus = false;
mpWindowImpl->mpFrameData->maPaintIdle.SetPriority( SchedulerPriority::REPAINT );
mpWindowImpl->mpFrameData->maPaintIdle.SetIdleHdl( LINK( this, Window, ImplHandlePaintHdl ) );
mpWindowImpl->mpFrameData->maPaintIdle.SetDebugName( "vcl::Window maPaintIdle" );
mpWindowImpl->mpFrameData->maResizeIdle.SetPriority( SchedulerPriority::RESIZE );
mpWindowImpl->mpFrameData->maResizeIdle.SetIdleHdl( LINK( this, Window, ImplHandleResizeTimerHdl ) );
mpWindowImpl->mpFrameData->maResizeIdle.SetDebugName( "vcl::Window maResizeIdle" );
mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = false;
if (!(nStyle & WB_DEFAULTWIN) && mpWindowImpl->mbDoubleBufferingRequested)
RequestDoubleBuffering(true);
mpWindowImpl->mpFrameData->mbInBufferedPaint = false;
if ( pRealParent && IsTopWindow() )
{
ImplWinData* pParentWinData = pRealParent->ImplGetWinData();
pParentWinData->maTopWindowChildren.push_back( this );
}
}
// init data
mpWindowImpl->mpRealParent = pRealParent;
// #99318: make sure fontcache and list is available before call to SetSettings
mpFontCollection = mpWindowImpl->mpFrameData->mpFontCollection;
mpFontCache = mpWindowImpl->mpFrameData->mpFontCache;
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() )
{
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().push_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.mpSettings );
OutputDevice::SetSettings( *pSVData->maAppData.mpSettings );
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( mnOutWidth, mnOutHeight );
}
else
{
if ( pParent )
{
if ( !ImplIsOverlapWindow() )
{
mpWindowImpl->mbDisabled = pParent->mpWindowImpl->mbDisabled;
mpWindowImpl->mbInputDisabled = pParent->mpWindowImpl->mbInputDisabled;
mpWindowImpl->meAlwaysInputMode = pParent->mpWindowImpl->meAlwaysInputMode;
}
if (!utl::ConfigManager::IsAvoidConfig())
OutputDevice::SetSettings( pParent->GetSettings() );
}
}
// setup the scale factor for Hi-DPI displays
mnDPIScalePercentage = CountDPIScaleFactor(mpWindowImpl->mpFrameData->mnDPIY);
mnDPIX = mpWindowImpl->mpFrameData->mnDPIX;
mnDPIY = mpWindowImpl->mpFrameData->mnDPIY;
if (!utl::ConfigManager::IsAvoidConfig())
{
const StyleSettings& rStyleSettings = mxSettings->GetStyleSettings();
maFont = rStyleSettings.GetAppFont();
if ( nStyle & WB_3DLOOK )
{
SetTextColor( rStyleSettings.GetButtonTextColor() );
SetBackground( Wallpaper( rStyleSettings.GetFaceColor() ) );
}
else
{
SetTextColor( rStyleSettings.GetWindowTextColor() );
SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) );
}
}
else
{
maFont = GetDefaultFont( DefaultFontType::FIXED, LANGUAGE_ENGLISH_US, GetDefaultFontFlags::NONE );
}
ImplPointToLogic(*this, 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 );
if ( GetAccessibleParentWindow() && GetParent() != Application::GetDefDialogParent() )
GetAccessibleParentWindow()->CallEventListeners( VCLEVENT_WINDOW_CHILDCREATED, this );
}
void Window::ImplInitAppFontData( vcl::Window* pWindow )
{
ImplSVData* pSVData = ImplGetSVData();
long nTextHeight = pWindow->GetTextHeight();
long nTextWidth = pWindow->approximate_char_width() * 8;
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 OS X, 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;
Rectangle aCtrlRegion( Point(), Size( nTextWidth < 10 ? 10 : nTextWidth, nTextHeight < 10 ? 10 : nTextHeight ) );
Rectangle aBoundingRgn( aCtrlRegion );
Rectangle aContentRgn( aCtrlRegion );
if( pWindow->GetNativeControlRegion( ControlType::Editbox, ControlPart::Entire, aCtrlRegion,
ControlState::ENABLED, aControlValue, OUString(),
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 = new ImplWinData;
mpWindowImpl->mpWinData->mbEnableNativeWidget = !(pNoNWF && *pNoNWF); // true: try to draw this control with native theme API
}
return mpWindowImpl->mpWinData;
}
void Window::CopyDeviceArea( SalTwoRect& aPosAry, bool bWindowInvalidate )
{
if (aPosAry.mnSrcWidth == 0 || aPosAry.mnSrcHeight == 0 || aPosAry.mnDestWidth == 0 || aPosAry.mnDestHeight == 0)
return;
if (bWindowInvalidate)
{
const Rectangle aSrcRect(Point(aPosAry.mnSrcX, aPosAry.mnSrcY),
Size(aPosAry.mnSrcWidth, aPosAry.mnSrcHeight));
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);
}
SalGraphics* Window::ImplGetFrameGraphics() const
{
if ( mpWindowImpl->mpFrameWindow->mpGraphics )
{
mpWindowImpl->mpFrameWindow->mbInitClipRegion = true;
}
else
{
OutputDevice* pFrameWinOutDev = mpWindowImpl->mpFrameWindow;
if ( ! pFrameWinOutDev->AcquireGraphics() )
{
return nullptr;
}
}
mpWindowImpl->mpFrameWindow->mpGraphics->ResetClipRegion();
return mpWindowImpl->mpFrameWindow->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;
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( VCLEVENT_WINDOW_SHOW, this );
// TODO. It's kind of a hack that we're re-using the VCLEVENT_WINDOW_SHOW. 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)
{
mnDPIX = mpWindowImpl->mpFrameData->mnDPIX;
mnDPIY = mpWindowImpl->mpFrameData->mnDPIY;
// setup the scale factor for Hi-DPI displays
mnDPIScalePercentage = CountDPIScaleFactor(mpWindowImpl->mpFrameData->mnDPIY);
const StyleSettings& rStyleSettings = mxSettings->GetStyleSettings();
SetPointFont(*this, rStyleSettings.GetAppFont());
}
else if ( mpWindowImpl->mpParent )
{
mnDPIX = mpWindowImpl->mpParent->mnDPIX;
mnDPIY = mpWindowImpl->mpParent->mnDPIY;
mnDPIScalePercentage = mpWindowImpl->mpParent->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& rRenderContext, vcl::Font& rFont) const
{
Size aSize = rFont.GetFontSize();
if (aSize.Width())
{
aSize.Width() *= mpWindowImpl->mpFrameData->mnDPIX;
aSize.Width() += 72 / 2;
aSize.Width() /= 72;
}
aSize.Height() *= mpWindowImpl->mpFrameData->mnDPIY;
aSize.Height() += 72/2;
aSize.Height() /= 72;
if (rRenderContext.IsMapModeEnabled())
aSize = rRenderContext.PixelToLogic(aSize);
rFont.SetFontSize(aSize);
}
void Window::ImplLogicToPoint(vcl::RenderContext& rRenderContext, vcl::Font& rFont) const
{
Size aSize = rFont.GetFontSize();
if (rRenderContext.IsMapModeEnabled())
aSize = rRenderContext.LogicToPixel(aSize);
if (aSize.Width())
{
aSize.Width() *= 72;
aSize.Width() += mpWindowImpl->mpFrameData->mnDPIX / 2;
aSize.Width() /= mpWindowImpl->mpFrameData->mnDPIX;
}
aSize.Height() *= 72;
aSize.Height() += mpWindowImpl->mpFrameData->mnDPIY / 2;
aSize.Height() /= mpWindowImpl->mpFrameData->mnDPIY;
rFont.SetFontSize(aSize);
}
bool Window::ImplUpdatePos()
{
bool bSysChild = false;
if ( ImplIsOverlapWindow() )
{
mnOutOffX = mpWindowImpl->mnX;
mnOutOffY = mpWindowImpl->mnY;
}
else
{
vcl::Window* pParent = ImplGetParent();
mnOutOffX = mpWindowImpl->mnX + pParent->mnOutOffX;
mnOutOffY = mpWindowImpl->mnY + pParent->mnOutOffY;
}
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( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight );
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->ImplUpdateSysObjPos();
pChild = pChild->mpWindowImpl->mpNext;
}
}
void Window::ImplPosSizeWindow( long nX, long nY,
long nWidth, long nHeight, PosSizeFlags nFlags )
{
bool bNewPos = false;
bool bNewSize = false;
bool bCopyBits = false;
long nOldOutOffX = mnOutOffX;
long nOldOutOffY = mnOutOffY;
long nOldOutWidth = mnOutWidth;
long nOldOutHeight = mnOutHeight;
vcl::Region* pOverlapRegion = nullptr;
vcl::Region* pOldRegion = nullptr;
if ( IsReallyVisible() )
{
Rectangle aOldWinRect( Point( nOldOutOffX, nOldOutOffY ),
Size( nOldOutWidth, nOldOutHeight ) );
pOldRegion = new vcl::Region( aOldWinRect );
if ( mpWindowImpl->mbWinRegion )
pOldRegion->Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
if ( mnOutWidth && 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 != mnOutWidth )
{
mnOutWidth = nWidth;
bNewSize = true;
bCopyBits = false;
}
}
if ( nFlags & PosSizeFlags::Height )
{
if ( nHeight < 0 )
nHeight = 0;
if ( nHeight != mnOutHeight )
{
mnOutHeight = nHeight;
bNewSize = true;
bCopyBits = false;
}
}
if ( nFlags & PosSizeFlags::X )
{
long nOrgX = nX;
// --- RTL --- (compare the screen coordinates)
Point aPtDev( Point( nX+mnOutOffX, 0 ) );
OutputDevice *pOutDev = GetOutDev();
if( pOutDev->HasMirroredGraphics() )
{
mpGraphics->mirror( aPtDev.X(), this );
// #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->ImplIsAntiparallel() )
{
// --- RTL --- (re-mirror at parent window)
nX = mpWindowImpl->mpParent->mnOutWidth - 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( ImplIsAntiparallel() )
{
aPtDev.X() = mpWindowImpl->mnAbsScreenX;
nOrgX = mpWindowImpl->maPos.X();
}
}
}
else if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() )
{
// mirrored window in LTR UI
{
// --- RTL --- (re-mirror at parent window)
nX = mpWindowImpl->mpParent->mnOutWidth - 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 = new vcl::Region();
ImplCalcOverlapRegion( Rectangle( Point( mnOutOffX, mnOutOffY ),
Size( mnOutWidth, mnOutHeight ) ),
*pOverlapRegion, false, true );
}
mpWindowImpl->mnX = nX;
mpWindowImpl->maPos.X() = nOrgX;
mpWindowImpl->mnAbsScreenX = aPtDev.X(); // --- RTL --- (store real screen pos)
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 = new vcl::Region();
ImplCalcOverlapRegion( Rectangle( Point( mnOutOffX, mnOutOffY ),
Size( mnOutWidth, mnOutHeight ) ),
*pOverlapRegion, false, true );
}
mpWindowImpl->mnY = nY;
mpWindowImpl->maPos.Y() = nY;
bNewPos = true;
}
}
if ( bNewPos || bNewSize )
{
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,
mnOutWidth-mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnRightBorder,
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 || (mnOutWidth > nOldOutWidth) || (mnOutHeight > nOldOutHeight) )
{
if ( bNewPos )
{
bool bInvalidate = false;
bool bParentPaint = true;
if ( !ImplIsOverlapWindow() )
bParentPaint = mpWindowImpl->mpParent->IsPaintEnabled();
if ( bCopyBits && bParentPaint && !HasPaintEvent() )
{
Point aPoint( mnOutOffX, mnOutOffY );
vcl::Region aRegion( Rectangle( aPoint,
Size( mnOutWidth, mnOutHeight ) ) );
if ( mpWindowImpl->mbWinRegion )
aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
ImplClipBoundaries( aRegion, false, true );
if ( !pOverlapRegion->IsEmpty() )
{
pOverlapRegion->Move( mnOutOffX-nOldOutOffX, mnOutOffY-nOldOutOffY );
aRegion.Exclude( *pOverlapRegion );
}
if ( !aRegion.IsEmpty() )
{
// adapt Paint areas
ImplMoveAllInvalidateRegions( Rectangle( Point( nOldOutOffX, nOldOutOffY ),
Size( nOldOutWidth, nOldOutHeight ) ),
mnOutOffX-nOldOutOffX, mnOutOffY-nOldOutOffY,
true );
SalGraphics* pGraphics = ImplGetFrameGraphics();
if ( pGraphics )
{
OutputDevice *pOutDev = GetOutDev();
const bool bSelectClipRegion = pOutDev->SelectClipRegion( aRegion, pGraphics );
if ( bSelectClipRegion )
{
pGraphics->CopyArea( mnOutOffX, mnOutOffY,
nOldOutOffX, nOldOutOffY,
nOldOutWidth, nOldOutHeight,
this );
}
else
bInvalidate = true;
}
else
bInvalidate = true;
if ( !bInvalidate )
{
if ( !pOverlapRegion->IsEmpty() )
ImplInvalidateFrameRegion( pOverlapRegion, InvalidateFlags::Children );
}
}
else
bInvalidate = true;
}
else
bInvalidate = true;
if ( bInvalidate )
ImplInvalidateFrameRegion( nullptr, InvalidateFlags::Children );
}
else
{
Point aPoint( mnOutOffX, mnOutOffY );
vcl::Region aRegion( Rectangle( aPoint,
Size( mnOutWidth, mnOutHeight ) ) );
aRegion.Exclude( *pOldRegion );
if ( mpWindowImpl->mbWinRegion )
aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
ImplClipBoundaries( aRegion, false, true );
if ( !aRegion.IsEmpty() )
ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
}
}
// invalidate Parent or Overlaps
if ( bNewPos ||
(mnOutWidth < nOldOutWidth) || (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( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight );
}
delete pOverlapRegion;
delete pOldRegion;
}
void Window::ImplNewInputContext()
{
ImplSVData* pSVData = ImplGetSVData();
vcl::Window* pFocusWin = pSVData->maWinData.mpFocusWin;
if ( !pFocusWin )
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();
LogicalFontInstance* pFontInstance = nullptr;
aNewContext.mpFont = nullptr;
if (!rFontName.isEmpty())
{
OutputDevice *pFocusWinOutDev = pFocusWin->GetOutDev();
Size aSize = pFocusWinOutDev->ImplLogicToDevicePixel( rFont.GetFontSize() );
if ( !aSize.Height() )
{
// only set default sizes if the font height in logical
// coordinates equals 0
if ( rFont.GetFontSize().Height() )
aSize.Height() = 1;
else
aSize.Height() = (12*pFocusWin->mnDPIY)/72;
}
pFontInstance = pFocusWin->mpFontCache->GetFontInstance( pFocusWin->mpFontCollection,
rFont, aSize, static_cast<float>(aSize.Height()) );
if ( pFontInstance )
aNewContext.mpFont = &pFontInstance->maFontSelData;
}
aNewContext.meLanguage = rFont.GetLanguage();
aNewContext.mnOptions = rInputContext.GetOptions();
pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext );
if ( pFontInstance )
pFocusWin->mpFontCache->Release( pFontInstance );
}
void Window::doLazyDelete()
{
SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(this);
DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(this);
if( pSysWin || ( pDockWin && pDockWin->IsFloatingMode() ) )
{
Show( false );
SetParent( ImplGetDefaultWindow() );
}
vcl::LazyDeletor::Delete( this );
}
KeyIndicatorState Window::GetIndicatorState() const
{
return mpWindowImpl->mpFrame->GetIndicatorState();
}
void Window::SimulateKeyPress( sal_uInt16 nKeyCode ) const
{
mpWindowImpl->mpFrame->SimulateKeyPress(nKeyCode);
}
void Window::KeyInput( const KeyEvent& rKEvt )
{
KeyCode cod = rKEvt.GetKeyCode ();
bool accel = ImplGetSVData()->maNWFData.mbEnableAccel;
bool autoacc = ImplGetSVData()->maNWFData.mbAutoAccel;
// do not respond to accelerators unless Alt is held */
if (cod.GetCode () >= 0x200 && cod.GetCode () <= 0x219)
{
if (!accel) return;
if (autoacc && cod.GetModifier () != KEY_MOD2) return;
}
NotifyEvent aNEvt( MouseNotifyEvent::KEYINPUT, this, &rKEvt );
if ( !CompatNotify( aNEvt ) )
mpWindowImpl->mbKeyInput = true;
}
void Window::KeyUp( const KeyEvent& rKEvt )
{
NotifyEvent aNEvt( MouseNotifyEvent::KEYUP, this, &rKEvt );
if ( !CompatNotify( aNEvt ) )
mpWindowImpl->mbKeyUp = true;
}
void Window::Draw( OutputDevice*, const Point&, const Size&, DrawFlags )
{
}
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( MouseNotifyEvent::GETFOCUS, this );
CompatNotify( aNEvt );
}
void Window::LoseFocus()
{
NotifyEvent aNEvt( MouseNotifyEvent::LOSEFOCUS, this );
CompatNotify( aNEvt );
}
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 = ImplGetParent()->OutputToScreenPixel( aPos );
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 = ImplGetParent()->OutputToScreenPixel( aPos );
Rectangle aRect( aPos, GetSizePixel() );
OUString aHelpText;
if ( !rStr.isEmpty() )
aHelpText = GetHelpText();
Help::ShowQuickHelp( this, aRect, rStr, aHelpText, QuickHelpFlags::CtrlText );
}
}
else
{
OUString aStrHelpId( OStringToOUString( GetHelpId(), RTL_TEXTENCODING_UTF8 ) );
if ( aStrHelpId.isEmpty() && ImplGetParent() )
ImplGetParent()->RequestHelp( rHEvt );
else
{
Help* pHelp = Application::GetHelp();
if ( pHelp )
{
if( !aStrHelpId.isEmpty() )
pHelp->Start( aStrHelpId, this );
else
pHelp->Start( OOO_HELP_INDEX, this );
}
}
}
}
void Window::Command( const CommandEvent& rCEvt )
{
CallEventListeners( VCLEVENT_WINDOW_COMMAND, const_cast<CommandEvent *>(&rCEvt) );
NotifyEvent aNEvt( MouseNotifyEvent::COMMAND, this, &rCEvt );
if ( !CompatNotify( aNEvt ) )
mpWindowImpl->mbCommand = true;
}
void Window::Tracking( const TrackingEvent& rTEvt )
{
ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this );
if( pWrapper )
pWrapper->Tracking( rTEvt );
}
void Window::StateChanged(StateChangedType eType)
{
switch (eType)
{
//stuff that doesn't invalidate the layout
case StateChangedType::ControlForeground:
case StateChangedType::ControlBackground:
case StateChangedType::Transparent:
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;
}
}
bool Window::IsLocked() const
{
if ( mpWindowImpl->mnLockCount != 0 )
return true;
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
if ( pChild->IsLocked() )
return true;
pChild = pChild->mpWindowImpl->mpNext;
}
return false;
}
void Window::SetStyle( WinBits nStyle )
{
if ( mpWindowImpl && mpWindowImpl->mnStyle != nStyle )
{
mpWindowImpl->mnPrevStyle = mpWindowImpl->mnStyle;
mpWindowImpl->mnStyle = nStyle;
CompatStateChanged( StateChangedType::Style );
}
}
void Window::SetExtendedStyle( WinBits nExtendedStyle )
{
if ( mpWindowImpl->mnExtendedStyle != nExtendedStyle )
{
vcl::Window* pWindow = ImplGetBorderWindow();
if( ! pWindow )
pWindow = this;
if( pWindow->mpWindowImpl->mbFrame )
{
SalExtStyle nExt = 0;
if( (nExtendedStyle & WB_EXT_DOCUMENT) )
nExt |= SAL_FRAME_EXT_STYLE_DOCUMENT;
if( (nExtendedStyle & WB_EXT_DOCMODIFIED) )
nExt |= SAL_FRAME_EXT_STYLE_DOCMODIFIED;
pWindow->ImplGetFrame()->SetExtendedFrameStyle( nExt );
}
mpWindowImpl->mnPrevExtendedStyle = mpWindowImpl->mnExtendedStyle;
mpWindowImpl->mnExtendedStyle = nExtendedStyle;
CompatStateChanged( StateChangedType::ExtendedStyle );
}
}
void Window::SetBorderStyle( WindowBorderStyle nBorderStyle )
{
if ( mpWindowImpl->mpBorderWindow )
{
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() == WINDOW_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() == WINDOW_BORDERWINDOW )
return static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->GetBorderStyle();
else
return mpWindowImpl->mpBorderWindow->GetBorderStyle();
}
return WindowBorderStyle::NONE;
}
long Window::CalcTitleWidth() const
{
if ( mpWindowImpl->mpBorderWindow )
{
if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_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<Window*>(this), rStyleSettings.GetTitleFont());
long nTitleWidth = GetTextWidth( GetText() );
const_cast<vcl::Window*>(this)->SetFont( aFont );
nTitleWidth += rStyleSettings.GetTitleHeight() * 3;
nTitleWidth += rStyleSettings.GetBorderSize() * 2;
nTitleWidth += 10;
return nTitleWidth;
}
return 0;
}
void Window::SetInputContext( const InputContext& rInputContext )
{
mpWindowImpl->maInputContext = rInputContext;
if ( !mpWindowImpl->mbInFocusHdl && HasFocus() )
ImplNewInputContext();
}
void Window::EndExtTextInput()
{
if ( mpWindowImpl->mbExtTextInput )
ImplGetFrame()->EndExtTextInput( EndExtTextInputFlags::Complete );
}
void Window::SetCursorRect( const Rectangle* pRect, long nExtTextInputWidth )
{
ImplWinData* pWinData = ImplGetWinData();
if ( pWinData->mpCursorRect )
{
if ( pRect )
*pWinData->mpCursorRect = *pRect;
else
{
delete pWinData->mpCursorRect;
pWinData->mpCursorRect = nullptr;
}
}
else
{
if ( pRect )
pWinData->mpCursorRect = new Rectangle( *pRect );
}
pWinData->mnCursorExtWidth = nExtTextInputWidth;
}
const Rectangle* Window::GetCursorRect() const
{
ImplWinData* pWinData = ImplGetWinData();
return pWinData->mpCursorRect;
}
long Window::GetCursorExtTextInputWidth() const
{
ImplWinData* pWinData = ImplGetWinData();
return pWinData->mnCursorExtWidth;
}
void Window::SetCompositionCharRect( const Rectangle* pRect, long nCompositionLength, bool bVertical ) {
ImplWinData* pWinData = ImplGetWinData();
delete[] pWinData->mpCompositionCharRects;
pWinData->mbVertical = bVertical;
pWinData->mpCompositionCharRects = nullptr;
pWinData->mnCompositionCharRects = nCompositionLength;
if ( pRect && (nCompositionLength > 0) )
{
pWinData->mpCompositionCharRects = new Rectangle[nCompositionLength];
for (long i = 0; i < nCompositionLength; ++i)
pWinData->mpCompositionCharRects[i] = pRect[i];
}
}
void Window::CollectChildren(::std::vector<vcl::Window *>& rAllChildren )
{
rAllChildren.push_back( this );
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->CollectChildren( rAllChildren );
pChild = pChild->mpWindowImpl->mpNext;
}
}
void Window::SetPointFont(vcl::RenderContext& rRenderContext, const vcl::Font& rFont)
{
vcl::Font aFont = rFont;
ImplPointToLogic(rRenderContext, aFont);
rRenderContext.SetFont(aFont);
}
vcl::Font Window::GetPointFont(vcl::RenderContext& rRenderContext) const
{
vcl::Font aFont = rRenderContext.GetFont();
ImplLogicToPoint(rRenderContext, aFont);
return aFont;
}
void Window::Show(bool bVisible, ShowFlags nFlags)
{
if ( IsDisposed() || mpWindowImpl->mbVisible == bVisible )
return;
VclPtr<vcl::Window> xWindow(this);
bool bRealVisibilityChanged = false;
mpWindowImpl->mbVisible = bVisible;
if ( !bVisible )
{
ImplHideAllOverlaps();
if( xWindow->IsDisposed() )
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->IsDisposed() )
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;
Rectangle aBounds( aInvRegion.GetBoundRect() );
aBounds.Left() -= workaround_border;
aBounds.Top() -= workaround_border;
aBounds.Right() += workaround_border;
aBounds.Bottom() += workaround_border;
aInvRegion = aBounds;
}
if ( !mpWindowImpl->mbNoParentUpdate && !(nFlags & ShowFlags::NoParentUpdate) )
{
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()->IsCompoundControl() &&
GetParent()->IsNativeWidgetEnabled() != IsNativeWidgetEnabled() )
{
EnableNativeWidget( GetParent()->IsNativeWidgetEnabled() );
}
if ( mpWindowImpl->mbCallMove )
{
ImplCallMove();
}
if ( mpWindowImpl->mbCallResize )
{
ImplCallResize();
}
CompatStateChanged( StateChangedType::Visible );
vcl::Window* pTestParent;
if ( ImplIsOverlapWindow() )
pTestParent = mpWindowImpl->mpOverlapWindow;
else
pTestParent = ImplGetParent();
if ( mpWindowImpl->mbFrame || pTestParent->mpWindowImpl->mbReallyVisible )
{
// if a window becomes visible, send all child windows a StateChange,
// such that these can initialise themselves
ImplCallInitShow();
// If it is a SystemWindow it automatically pops up on top of
// all other windows if needed.
if ( ImplIsOverlapWindow() && !(nFlags & ShowFlags::NoActivate) )
{
ImplStartToTop(( nFlags & ShowFlags::ForegroundTask ) ? ToTopFlags::ForegroundTask : ToTopFlags::NONE );
ImplFocusToTop( ToTopFlags::NONE, false );
}
// adjust mpWindowImpl->mbReallyVisible
bRealVisibilityChanged = !mpWindowImpl->mbReallyVisible;
ImplSetReallyVisible();
// assure clip rectangles will be recalculated
ImplSetClipFlag();
if ( !mpWindowImpl->mbFrame )
{
InvalidateFlags nInvalidateFlags = InvalidateFlags::Children;
if( ! IsPaintTransparent() )
nInvalidateFlags |= InvalidateFlags::NoTransparent;
ImplInvalidate( nullptr, nInvalidateFlags );
ImplGenerateMouseMove();
}
}
if ( mpWindowImpl->mpBorderWindow )
mpWindowImpl->mpBorderWindow->Show( true, nFlags );
else if ( mpWindowImpl->mbFrame )
{
// #106431#, hide SplashScreen
ImplSVData* pSVData = ImplGetSVData();
if ( !pSVData->mpIntroWindow )
{
// The right way would be just to call this (not even in the 'if')
GetpApp()->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::GetSettings().GetMiscSettings().GetPseudoHeadless())
{
bool bNoActivate(nFlags & (ShowFlags::NoActivate|ShowFlags::NoFocusChange));
mpWindowImpl->mpFrame->Show( true, bNoActivate );
}
if( xWindow->IsDisposed() )
return;
// Query the correct size of the window, if we are waiting for
// a system resize
if ( mpWindowImpl->mbWaitSystemResize )
{
long nOutWidth;
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->IsDisposed() )
return;
ImplShowAllOverlaps();
}
if( xWindow->IsDisposed() )
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 ? VCLEVENT_WINDOW_SHOW : VCLEVENT_WINDOW_HIDE );
if( xWindow->IsDisposed() )
return;
}
Size Window::GetSizePixel() const
{
if (!mpWindowImpl)
{
SAL_WARN("vcl.layout", "WTF no windowimpl");
return Size(0,0);
}
// #i43257# trigger pending resize handler to assure correct window sizes
if( mpWindowImpl->mpFrameData->maResizeIdle.IsActive() )
{
VclPtr<vcl::Window> xWindow( const_cast<Window*>(this) );
mpWindowImpl->mpFrameData->maResizeIdle.Stop();
mpWindowImpl->mpFrameData->maResizeIdle.GetIdleHdl().Call( nullptr );
if( xWindow->IsDisposed() )
return Size(0,0);
}
return Size( mnOutWidth+mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder,
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() == WINDOW_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->maWinData.mpFocusWin == nullptr &&
mpWindowImpl->mpFrameData->mbHasFocus &&
mpWindowImpl->mpFrameData->mpFocusWin == this )
pSVData->maWinData.mpFocusWin = this;
if ( mpWindowImpl->mbDisabled != !bEnable )
{
mpWindowImpl->mbDisabled = !bEnable;
if ( mpWindowImpl->mpSysObj )
mpWindowImpl->mpSysObj->Enable( bEnable && !mpWindowImpl->mbInputDisabled );
CompatStateChanged( StateChangedType::Enable );
CallEventListeners( bEnable ? VCLEVENT_WINDOW_ENABLED : VCLEVENT_WINDOW_DISABLED );
}
if ( bChild )
{
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->Enable( bEnable, bChild );
pChild = pChild->mpWindowImpl->mpNext;
}
}
if ( IsReallyVisible() )
ImplGenerateMouseMove();
}
void Window::SetCallHandlersOnInputDisabled( bool bCall )
{
mpWindowImpl->mbCallHandlersDuringInputDisabled = bCall;
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->SetCallHandlersOnInputDisabled( bCall );
pChild = pChild->mpWindowImpl->mpNext;
}
}
bool Window::IsCallHandlersOnInputDisabled() const
{
return mpWindowImpl->mbCallHandlersDuringInputDisabled;
}
void Window::EnableInput( bool bEnable, bool bChild )
{
bool bNotify = (bEnable != mpWindowImpl->mbInputDisabled);
if ( mpWindowImpl->mpBorderWindow )
{
mpWindowImpl->mpBorderWindow->EnableInput( bEnable, false );
if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) &&
static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow )
static_cast<ImplBorderWindow*>(mpWindowImpl->mpBorderWindow.get())->mpMenuBarWindow->EnableInput( bEnable );
}
if ( (! bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled) ||
( bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputDisabled) )
{
// 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->maWinData.mpFocusWin == nullptr &&
mpWindowImpl->mpFrameData->mbHasFocus &&
mpWindowImpl->mpFrameData->mpFocusWin == this )
pSVData->maWinData.mpFocusWin = this;
if ( bChild )
{
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->EnableInput( bEnable, bChild );
pChild = pChild->mpWindowImpl->mpNext;
}
}
if ( IsReallyVisible() )
ImplGenerateMouseMove();
// #104827# notify parent
if ( bNotify )
{
NotifyEvent aNEvt( bEnable ? MouseNotifyEvent::INPUTENABLE : MouseNotifyEvent::INPUTDISABLE, this );
CompatNotify( aNEvt );
}
}
void Window::EnableInput( bool bEnable, const vcl::Window* pExcludeWindow )
{
EnableInput( bEnable );
// pExecuteWindow is the first Overlap-Frame --> if this
// shouldn't be the case, than 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, than 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()->maWinData.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, than 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 )
{
::std::vector< VclPtr<vcl::Window> >& rList = mpWindowImpl->mpFrameData->maOwnerDrawList;
auto p = rList.begin();
while( p != rList.end() )
{
// Is Window in the path from this window
if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( (*p), true ) )
{
// Is Window not in the exclude window path or not the
// exclude window, than change the status
if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( (*p), true ) )
(*p)->EnableInput( bEnable );
}
++p;
}
}
}
void Window::AlwaysEnableInput( bool bAlways, bool bChild )
{
if ( mpWindowImpl->mpBorderWindow )
mpWindowImpl->mpBorderWindow->AlwaysEnableInput( bAlways, false );
if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled )
{
mpWindowImpl->meAlwaysInputMode = AlwaysInputEnabled;
if ( bAlways )
EnableInput( true, false );
}
else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputEnabled )
{
mpWindowImpl->meAlwaysInputMode = AlwaysInputNone;
}
if ( bChild )
{
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->AlwaysEnableInput( bAlways, bChild );
pChild = pChild->mpWindowImpl->mpNext;
}
}
}
void Window::AlwaysDisableInput( bool bAlways, bool bChild )
{
if ( mpWindowImpl->mpBorderWindow )
mpWindowImpl->mpBorderWindow->AlwaysDisableInput( bAlways, false );
if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputDisabled )
{
mpWindowImpl->meAlwaysInputMode = AlwaysInputDisabled;
if ( bAlways )
EnableInput( false, false );
}
else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputDisabled )
{
mpWindowImpl->meAlwaysInputMode = AlwaysInputNone;
}
if ( bChild )
{
vcl::Window* pChild = mpWindowImpl->mpFirstChild;
while ( pChild )
{
pChild->AlwaysDisableInput( bAlways, bChild );
pChild = pChild->mpWindowImpl->mpNext;
}
}
}
void Window::SetActivateMode( ActivateModeFlags nMode )
{
if ( mpWindowImpl->mpBorderWindow )
mpWindowImpl->mpBorderWindow->SetActivateMode( nMode );
if ( mpWindowImpl->mnActivateMode != nMode )
{
mpWindowImpl->mnActivateMode = nMode;
// possibly trigger Decativate/Activate
if ( mpWindowImpl->mnActivateMode != ActivateModeFlags::NONE )
{
if ( (mpWindowImpl->mbActive || (GetType() == WINDOW_BORDERWINDOW)) &&
!HasChildPathFocus( true ) )
{
mpWindowImpl->mbActive = false;
Deactivate();
}
}
else
{
if ( !mpWindowImpl->mbActive || (GetType() == WINDOW_BORDERWINDOW) )
{
mpWindowImpl->mbActive = true;
Activate();
}
}
}
}
void Window::setPosSizePixel( long nX, long nY,
long nWidth, 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
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)
long nOldWidth = pWindow->mnOutWidth;
if ( !(nFlags & PosSizeFlags::Width) )
nWidth = pWindow->mnOutWidth;
if ( !(nFlags & PosSizeFlags::Height) )
nHeight = pWindow->mnOutHeight;
sal_uInt16 nSysFlags=0;
vcl::Window *pParent = 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( pParent && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) )
{
nX += pParent->mnOutOffX;
}
if( pParent && pParent->ImplIsAntiparallel() )
{
// --- RTL --- (re-mirror at parent window)
Rectangle aRect( Point ( nX, nY ), Size( nWidth, nHeight ) );
const OutputDevice *pParentOutDev = pParent->GetOutDev();
pParentOutDev->ReMirror( aRect );
nX = aRect.Left();
}
}
if( !(nFlags & PosSizeFlags::X) && bHasValidSize && pWindow->mpWindowImpl->mpFrame->maGeometry.nWidth )
{
// --- RTL --- make sure the old right aligned position is not changed
// system windows will always grow to the right
if ( pParent )
{
OutputDevice *pParentOutDev = pParent->GetOutDev();
if( pParentOutDev->HasMirroredGraphics() )
{
long myWidth = nOldWidth;
if( !myWidth )
myWidth = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nWidth;
if( !myWidth )
myWidth = nWidth;
nFlags |= PosSizeFlags::X;
nSysFlags |= SAL_FRAME_POSSIZE_X;
nX = pParent->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX - mpWindowImpl->mpFrame->GetUnmirroredGeometry().nLeftDecoration +
pParent->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nWidth - myWidth - 1 - mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX;
if(!(nFlags & PosSizeFlags::Y))
{
nFlags |= PosSizeFlags::Y;
nSysFlags |= SAL_FRAME_POSSIZE_Y;
nY = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nY - pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nY -
mpWindowImpl->mpFrame->GetUnmirroredGeometry().nTopDecoration;
}
}
}
}
if( nFlags & PosSizeFlags::Y )
{
nSysFlags |= SAL_FRAME_POSSIZE_Y;
if( pParent && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) )
{
nY += pParent->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 );
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 );
// 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 to small or to large.
ImplHandleResize( pWindow, nWidth, nHeight );
}
else
{
pWindow->ImplPosSizeWindow( nX, nY, nWidth, nHeight, nFlags );
if ( IsReallyVisible() )
ImplGenerateMouseMove();
}
}
Point Window::GetPosPixel() const
{
return mpWindowImpl->maPos;
}
Rectangle Window::GetDesktopRectPixel() const
{
Rectangle rRect;
mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrame->GetWorkArea( rRect );
return rRect;
}
Point Window::OutputToScreenPixel( const Point& rPos ) const
{
// relative to top level parent
return Point( rPos.X()+mnOutOffX, rPos.Y()+mnOutOffY );
}
Point Window::ScreenToOutputPixel( const Point& rPos ) const
{
// relative to top level parent
return Point( rPos.X()-mnOutOffX, rPos.Y()-mnOutOffY );
}
long Window::ImplGetUnmirroredOutOffX()
{
// revert mnOutOffX changes that were potentially made in ImplPosSizeWindow
long offx = mnOutOffX;
OutputDevice *pOutDev = GetOutDev();
if( pOutDev->HasMirroredGraphics() )
{
if( mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() )
{
if ( !ImplIsOverlapWindow() )
offx -= mpWindowImpl->mpParent->mnOutOffX;
offx = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - offx;
if ( !ImplIsOverlapWindow() )
offx += mpWindowImpl->mpParent->mnOutOffX;
}
}
return offx;
}
// normalized screen pixel are independent of mirroring
Point Window::OutputToNormalizedScreenPixel( const Point& rPos ) const
{
// relative to top level parent
long offx = const_cast<vcl::Window*>(this)->ImplGetUnmirroredOutOffX();
return Point( rPos.X()+offx, rPos.Y()+mnOutOffY );
}
Point Window::NormalizedScreenToOutputPixel( const Point& rPos ) const
{
// relative to top level parent
long offx = const_cast<vcl::Window*>(this)->ImplGetUnmirroredOutOffX();
return Point( rPos.X()-offx, rPos.Y()-mnOutOffY );
}
Point Window::OutputToAbsoluteScreenPixel( const Point& rPos ) const
{
// relative to the screen
Point p = OutputToScreenPixel( rPos );
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
p.X() += g.nX;
p.Y() += g.nY;
return p;
}
Point Window::AbsoluteScreenToOutputPixel( const Point& rPos ) const
{
// relative to the screen
Point p = ScreenToOutputPixel( rPos );
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
p.X() -= g.nX;
p.Y() -= g.nY;
return p;
}
Rectangle Window::ImplOutputToUnmirroredAbsoluteScreenPixel( const 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 = OutputToScreenPixel( rRect.TopRight() );
p1.X() = g.nX+g.nWidth-p1.X();
p1.Y() += g.nY;
Point p2 = OutputToScreenPixel( rRect.BottomLeft() );
p2.X() = g.nX+g.nWidth-p2.X();
p2.Y() += g.nY;
return Rectangle( p1, p2 );
}
Rectangle Window::GetWindowExtentsRelative( vcl::Window *pRelativeWindow ) const
{
// with decoration
return ImplGetWindowExtentsRelative( pRelativeWindow, false );
}
Rectangle Window::GetClientWindowExtentsRelative() const
{
// without decoration
return ImplGetWindowExtentsRelative( nullptr, true );
}
Rectangle Window::ImplGetWindowExtentsRelative( vcl::Window *pRelativeWindow, bool bClientOnly ) const
{
SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry();
// make sure we use the extent of our border window,
// otherwise we miss a few pixels
const vcl::Window *pWin = (!bClientOnly && mpWindowImpl->mpBorderWindow) ? mpWindowImpl->mpBorderWindow : this;
Point aPos( pWin->OutputToScreenPixel( Point(0,0) ) );
aPos.X() += g.nX;
aPos.Y() += g.nY;
Size aSize ( pWin->GetSizePixel() );
// #104088# do not add decoration to the workwindow to be compatible to java accessibility api
if( !bClientOnly && (mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame && GetType() != WINDOW_WORKWINDOW)) )
{
aPos.X() -= g.nLeftDecoration;
aPos.Y() -= g.nTopDecoration;
aSize.Width() += g.nLeftDecoration + g.nRightDecoration;
aSize.Height() += g.nTopDecoration + g.nBottomDecoration;
}
if( pRelativeWindow )
{
// #106399# express coordinates relative to borderwindow
vcl::Window *pRelWin = (!bClientOnly && pRelativeWindow->mpWindowImpl->mpBorderWindow) ? pRelativeWindow->mpWindowImpl->mpBorderWindow.get() : pRelativeWindow;
aPos = pRelWin->AbsoluteScreenToOutputPixel( aPos );
}
return Rectangle( aPos, aSize );
}
void Window::Scroll( long nHorzScroll, long nVertScroll, ScrollFlags nFlags )
{
ImplScroll( Rectangle( Point( mnOutOffX, mnOutOffY ),
Size( mnOutWidth, mnOutHeight ) ),
nHorzScroll, nVertScroll, nFlags & ~ScrollFlags::Clip );
}
void Window::Scroll( long nHorzScroll, long nVertScroll,
const Rectangle& rRect, ScrollFlags nFlags )
{
OutputDevice *pOutDev = GetOutDev();
Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
aRect.Intersection( Rectangle( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ) );
if ( !aRect.IsEmpty() )
ImplScroll( aRect, nHorzScroll, nVertScroll, nFlags );
}
void Window::Flush()
{
const Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
mpWindowImpl->mpFrame->Flush( aWinRect );
}
void Window::SetUpdateMode( bool bUpdate )
{
mpWindowImpl->mbNoUpdate = !bUpdate;
CompatStateChanged( StateChangedType::UpdateMode );
}
void Window::GrabFocus()
{
ImplGrabFocus( GetFocusFlags::NONE );
}
bool Window::HasFocus() const
{
return (this == ImplGetSVData()->maWinData.mpFocusWin);
}
void Window::GrabFocusToDocument()
{
ImplGrabFocusToDocument(GetFocusFlags::NONE);
}
void Window::SetFakeFocus( bool bFocus )
{
ImplGetWindowImpl()->mbFakeFocusSet = bFocus;
}
bool Window::HasChildPathFocus( bool bSystemWindow ) const
{
vcl::Window* pFocusWin = ImplGetSVData()->maWinData.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( VCLEVENT_WINDOW_FRAMETITLECHANGED, &oldTitle );
// #107247# needed for accessibility
// The VCLEVENT_WINDOW_FRAMETITLECHANGED 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( VCLEVENT_WINDOW_FRAMETITLECHANGED, &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 )
{
if( 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().GetColor() == COL_TRANSPARENT &&
mpWindowImpl->mpParent )
return mpWindowImpl->mpParent->GetDisplayBackground();
return rBack;
}
const OUString& Window::GetHelpText() const
{
OUString aStrHelpId( OStringToOUString( GetHelpId(), RTL_TEXTENCODING_UTF8 ) );
bool bStrHelpId = !aStrHelpId.isEmpty();
if ( !mpWindowImpl->maHelpText.getLength() && bStrHelpId )
{
if ( !IsDialog() && (mpWindowImpl->mnType != WINDOW_TABPAGE) && (mpWindowImpl->mnType != WINDOW_FLOATINGWINDOW) )
{
Help* pHelp = Application::GetHelp();
if ( pHelp )
{
mpWindowImpl->maHelpText = pHelp->GetHelpText(aStrHelpId, this);
mpWindowImpl->mbHelpTextDynamic = false;
}
}
}
else if( mpWindowImpl->mbHelpTextDynamic && bStrHelpId )
{
static const char* pEnv = getenv( "HELP_DEBUG" );
if( pEnv && *pEnv )
{
OUStringBuffer aTxt( 64+mpWindowImpl->maHelpText.getLength() );
aTxt.append( mpWindowImpl->maHelpText );
aTxt.append( "\n------------------\n" );
aTxt.append( OUString( aStrHelpId ) );
mpWindowImpl->maHelpText = aTxt.makeStringAndClear();
}
mpWindowImpl->mbHelpTextDynamic = false;
}
return mpWindowImpl->maHelpText;
}
void Window::SetWindowPeer( Reference< css::awt::XWindowPeer > const & xPeer, VCLXWindow* pVCLXWindow )
{
assert(mpWindowImpl);
// be safe against re-entrance: first clear the old ref, then assign the new one
mpWindowImpl->mxWindowPeer.clear();
mpWindowImpl->mxWindowPeer = xPeer;
mpWindowImpl->mpVCLXWindow = pVCLXWindow;
}
Reference< css::awt::XWindowPeer > Window::GetComponentInterface( bool bCreate )
{
if ( !mpWindowImpl->mxWindowPeer.is() && bCreate )
{
UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
if ( pWrapper )
mpWindowImpl->mxWindowPeer = pWrapper->GetWindowInterface( this );
}
return mpWindowImpl->mxWindowPeer;
}
void Window::SetComponentInterface( Reference< css::awt::XWindowPeer > const & xIFace )
{
UnoWrapperBase* pWrapper = Application::GetUnoWrapper();
SAL_WARN_IF( !pWrapper, "vcl", "SetComponentInterface: No Wrapper!" );
if ( pWrapper )
pWrapper->SetWindowInterface( this, xIFace );
}
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( VCLEVENT_WINDOW_DEACTIVATE );
if( xWindow->IsDisposed() )
return;
// #100759#, avoid walking the wrong frame's hierarchy
// eg, undocked docking windows (ImplDockFloatWin)
if ( ImplGetParent() && 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 ) )
{
VclPtr<vcl::Window> xWindow(this);
CallEventListeners( VCLEVENT_WINDOW_ACTIVATE, pOld );
if( xWindow->IsDisposed() )
return;
if ( ImplGetParent() )
ImplGetParent()->ImplCallActivateListeners( pOld );
else if( (mpWindowImpl->mnStyle & WB_INTROWIN) == 0 )
{
// top level frame reached: store hint for DefModalDialogParent
ImplGetSVData()->maWinData.mpActiveApplicationFrame = mpWindowImpl->mpFrameWindow;
}
}
}
void Window::SetClipboard(Reference<XClipboard> const & xClipboard)
{
if (mpWindowImpl->mpFrameData)
mpWindowImpl->mpFrameData->mxClipboard = xClipboard;
}
Reference< XClipboard > Window::GetClipboard()
{
if( mpWindowImpl->mpFrameData )
{
if( ! mpWindowImpl->mpFrameData->mxClipboard.is() )
{
try
{
mpWindowImpl->mpFrameData->mxClipboard
= css::datatransfer::clipboard::SystemClipboard::create(
comphelper::getProcessComponentContext());
}
catch (DeploymentException & e)
{
SAL_WARN(
"vcl.window",
"ignoring DeploymentException \"" << e.Message << "\"");
}
}
return mpWindowImpl->mpFrameData->mxClipboard;
}
return static_cast < XClipboard * > (nullptr);
}
Reference< XClipboard > Window::GetPrimarySelection()
{
if( mpWindowImpl->mpFrameData )
{
if( ! mpWindowImpl->mpFrameData->mxSelection.is() )
{
try
{
Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
#if HAVE_FEATURE_X11
// A hack, making the primary selection available as an instance
// of the SystemClipboard service on X11:
Sequence< Any > args(1);
args[0] <<= OUString("PRIMARY");
mpWindowImpl->mpFrameData->mxSelection.set(
(xContext->getServiceManager()->
createInstanceWithArgumentsAndContext(
"com.sun.star.datatransfer.clipboard.SystemClipboard",
args, xContext)),
UNO_QUERY_THROW);
#else
static Reference< XClipboard > s_xSelection(
xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.datatransfer.clipboard.GenericClipboard", xContext ), UNO_QUERY );
mpWindowImpl->mpFrameData->mxSelection = s_xSelection;
#endif
}
catch (RuntimeException & e)
{
SAL_WARN(
"vcl.window",
"ignoring RuntimeException \"" << e.Message << "\"");
}
}
return mpWindowImpl->mpFrameData->mxSelection;
}
return static_cast < XClipboard * > (nullptr);
}
void Window::RecordLayoutData( vcl::ControlLayoutData* pLayout, const Rectangle& rRect )
{
assert(mpOutDevData);
mpOutDevData->mpRecordLayout = pLayout;
mpOutDevData->maRecordRect = rRect;
Paint(*this, rRect);
mpOutDevData->mpRecordLayout = nullptr;
}
void Window::DrawSelectionBackground( const 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() == Color( COL_WHITE ) );
int c1 = aSelectionBorderCol.GetLuminance();
int c2 = GetDisplayBackground().GetColor().GetLuminance();
if( !bDark && !bBright && abs( c2-c1 ) < 75 )
{
// constrast too low
sal_uInt16 h,s,b;
aSelectionFillCol.RGBtoHSB( h, s, b );
if( b > 50 ) b -= 40;
else b += 40;
aSelectionFillCol.SetColor( Color::HSBtoRGB( h, s, b ) );
aSelectionBorderCol = aSelectionFillCol;
}
Rectangle aRect( rRect );
Color oldFillCol = GetFillColor();
Color oldLineCol = GetLineColor();
if( bDrawBorder )
SetLineColor( bDark ? Color(COL_WHITE) : ( bBright ? Color(COL_BLACK) : aSelectionBorderCol ) );
else
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;
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;
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;
SetLineColor( COL_BLACK );
if( highlight == 3 )
nPercent = 80;
else
nPercent = 0;
}
else
nPercent = 70; // selected ( dark )
}
}
SetFillColor( aSelectionFillCol );
if( bDark )
{
DrawRect( aRect );
}
else
{
tools::Polygon aPoly( aRect );
tools::PolyPolygon aPolyPoly( aPoly );
DrawTransparent( aPolyPoly, nPercent );
}
SetFillColor( oldFillCol );
SetLineColor( oldLineCol );
}
bool Window::IsScrollable() const
{
// check for scrollbars
vcl::Window *pChild = mpWindowImpl->mpFirstChild;
while( pChild )
{
if( pChild->GetType() == WINDOW_SCROLLBAR )
return true;
else
pChild = pChild->mpWindowImpl->mpNext;
}
return false;
}
void Window::ImplMirrorFramePos( Point &pt ) const
{
pt.X() = mpWindowImpl->mpFrame->maGeometry.nWidth-1-pt.X();
}
// frame based modal counter (dialogs are not modal to the whole application anymore)
bool Window::IsInModalMode() const
{
return (mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mnModalMode != 0);
}
void Window::ImplIncModalCount()
{
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::ImplDecModalCount()
{
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 ? VCLEVENT_WINDOW_MINIMIZE : VCLEVENT_WINDOW_NORMALIZE );
// #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 ? VCLEVENT_WINDOW_MINIMIZE : VCLEVENT_WINDOW_NORMALIZE );
}
bool Window::HasActiveChildFrame()
{
bool bRet = false;
vcl::Window *pFrameWin = ImplGetSVData()->maWinData.mpFirstFrame;
while( pFrameWin )
{
if( pFrameWin != mpWindowImpl->mpFrameWindow )
{
bool bDecorated = false;
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)->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, mxSettings.get(), AllSettingsFlags::STYLE );
CompatDataChanged( aDCEvt );
// sometimes the borderwindow is queried, so keep it in sync
if( mpWindowImpl->mpBorderWindow )
mpWindowImpl->mpBorderWindow->ImplGetWinData()->mbEnableNativeWidget = bEnable;
}
// push down, useful for compound controls
vcl::Window *pChild = mpWindowImpl->mpFirstChild;
while( pChild )
{
pChild->EnableNativeWidget( bEnable );
pChild = pChild->mpWindowImpl->mpNext;
}
}
bool Window::IsNativeWidgetEnabled() const
{
return ImplGetWinData()->mbEnableNativeWidget;
}
Reference< css::rendering::XCanvas > Window::ImplGetCanvas( bool bSpriteCanvas ) const
{
// try to retrieve hard reference from weak member
Reference< css::rendering::XCanvas > xCanvas( mpWindowImpl->mxCanvas );
// canvas still valid? Then we're done.
if( xCanvas.is() )
return xCanvas;
Sequence< Any > aArg(6);
// Feed any with operating system's window handle
// common: first any is VCL pointer to window (for VCL canvas)
aArg[ 0 ] = makeAny( reinterpret_cast<sal_Int64>(this) );
aArg[ 1 ] = GetSystemDataAny();
aArg[ 2 ] = makeAny( css::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ) );
aArg[ 3 ] = makeAny( mpWindowImpl->mbAlwaysOnTop );
aArg[ 4 ] = makeAny( Reference< css::awt::XWindow >(
const_cast<vcl::Window*>(this)->GetComponentInterface(),
UNO_QUERY ));
aArg[ 5 ] = GetSystemGfxDataAny();
Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
// Create canvas instance with window handle
static vcl::DeleteUnoReferenceOnDeinit<XMultiComponentFactory> xStaticCanvasFactory(
css::rendering::CanvasFactory::create( xContext ) );
Reference<XMultiComponentFactory> xCanvasFactory(xStaticCanvasFactory.get());
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* >( mpWindowImpl->mpFrame )->mnDisplay;
if( (nDisplay >= Application::GetScreenCount()) )
{
xCanvas.set( xCanvasFactory->createInstanceWithArgumentsAndContext(
bSpriteCanvas ?
OUString( "com.sun.star.rendering.SpriteCanvas.MultiScreen" ) :
OUString( "com.sun.star.rendering.Canvas.MultiScreen" ),
aArg,
xContext ),
UNO_QUERY );
}
else
{
#endif
xCanvas.set( xCanvasFactory->createInstanceWithArgumentsAndContext(
bSpriteCanvas ?
OUString( "com.sun.star.rendering.SpriteCanvas" ) :
OUString( "com.sun.star.rendering.Canvas" ),
aArg,
xContext ),
UNO_QUERY );
#ifdef _WIN32
}
#endif
mpWindowImpl->mxCanvas = xCanvas;
}
// no factory??? Empty reference, then.
return xCanvas;
}
Reference< css::rendering::XCanvas > Window::GetCanvas() const
{
return ImplGetCanvas( false );
}
Reference< css::rendering::XSpriteCanvas > Window::GetSpriteCanvas() const
{
Reference< css::rendering::XSpriteCanvas > xSpriteCanvas(
ImplGetCanvas( true ), UNO_QUERY );
return xSpriteCanvas;
}
OUString Window::GetSurroundingText() const
{
return OUString();
}
Selection Window::GetSurroundingTextSelection() const
{
return Selection( 0, 0 );
}
bool Window::UsePolyPolygonForComplexGradient()
{
if ( meRasterOp != RasterOp::OverPaint )
return true;
return false;
}
void Window::ApplySettings(vcl::RenderContext& /*rRenderContext*/)
{
}
const SystemEnvData* Window::GetSystemData() const
{
return mpWindowImpl->mpFrame ? mpWindowImpl->mpFrame->GetSystemData() : nullptr;
}
Any Window::GetSystemDataAny() const
{
Any aRet;
const SystemEnvData* pSysData = GetSystemData();
if( pSysData )
{
Sequence< sal_Int8 > aSeq( reinterpret_cast<sal_Int8 const *>(pSysData), pSysData->nSize );
aRet <<= aSeq;
}
return aRet;
}
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 rational here is that we moved destructors to
* dispose and this altered a lot of code paths, that
* are better left unchanged for now.
*/
#define COMPAT_BODY(method,args) \
if (!mpWindowImpl || mpWindowImpl->mbInDispose) \
Window::method args; \
else \
method args;
void Window::CompatGetFocus()
{
COMPAT_BODY(GetFocus,())
}
void Window::CompatLoseFocus()
{
COMPAT_BODY(LoseFocus,())
}
void Window::CompatStateChanged( StateChangedType nStateChange )
{
COMPAT_BODY(StateChanged,(nStateChange))
}
void Window::CompatDataChanged( const DataChangedEvent& rDCEvt )
{
COMPAT_BODY(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::Notify( rNEvt );
else
return Notify( rNEvt );
}
void Window::set_id(const OUString& rID)
{
mpWindowImpl->maID = rID;
}
const OUString& Window::get_id() const
{
return mpWindowImpl->maID;
}
FactoryFunction Window::GetUITestFactory() const
{
return WindowUIObject::create;
}
} /* namespace vcl */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */