diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/source/awt/vclxtoolkit.cxx | 2639 |
1 files changed, 2639 insertions, 0 deletions
diff --git a/toolkit/source/awt/vclxtoolkit.cxx b/toolkit/source/awt/vclxtoolkit.cxx new file mode 100644 index 000000000..b7f6f2f43 --- /dev/null +++ b/toolkit/source/awt/vclxtoolkit.cxx @@ -0,0 +1,2639 @@ +/* -*- 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 . + */ + +#ifdef _WIN32 +#include <prewin.h> +#include <postwin.h> +#endif +#include <config_features.h> +#include <com/sun/star/awt/WindowAttribute.hpp> +#include <com/sun/star/awt/VclWindowPeerAttribute.hpp> +#include <com/sun/star/awt/WindowClass.hpp> +#include <com/sun/star/awt/MessageBoxButtons.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/SystemDependent.hpp> +#include <com/sun/star/awt/FocusEvent.hpp> +#include <com/sun/star/awt/KeyEvent.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/awt/XToolkitExperimental.hpp> +#include <com/sun/star/awt/XToolkitRobot.hpp> + +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/conditn.hxx> +#include <osl/module.h> +#include <osl/thread.hxx> +#include <osl/mutex.hxx> +#include <rtl/process.h> +#include <sal/log.hxx> +#include <tools/link.hxx> +#include <tools/wintypes.hxx> + +#ifdef MACOSX +#include <premac.h> +#include <Cocoa/Cocoa.h> +#include <postmac.h> +#endif + +#include <vcl/sysdata.hxx> +#include <vcl/textrectinfo.hxx> +#include <vcl/vclmedit.hxx> + +#include <toolkit/awt/vclxwindows.hxx> +#include <awt/vclxsystemdependentwindow.hxx> +#include <awt/vclxregion.hxx> +#include <awt/vclxtabpagecontainer.hxx> + +#include <awt/animatedimagespeer.hxx> +#include <toolkit/awt/vclxtopwindow.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <toolkit/helper/property.hxx> + +#include <toolkit/helper/convert.hxx> +#include <controls/filectrl.hxx> +#include <controls/treecontrolpeer.hxx> +#include <vcl/toolkit/button.hxx> +#include <vcl/toolkit/combobox.hxx> +#include <vcl/ctrl.hxx> +#include <vcl/toolkit/dialog.hxx> +#include <vcl/dockingarea.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/edit.hxx> +#include <vcl/event.hxx> +#include <vcl/toolkit/field.hxx> +#include <vcl/fixed.hxx> +#include <vcl/toolkit/fixedhyper.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/fmtfield.hxx> +#include <vcl/toolkit/prgsbar.hxx> +#include <vcl/scheduler.hxx> +#include <vcl/longcurr.hxx> +#include <vcl/lstbox.hxx> +#include <vcl/menubtn.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/scrbar.hxx> +#include <vcl/split.hxx> +#include <vcl/splitwin.hxx> +#include <vcl/status.hxx> +#include <vcl/svapp.hxx> +#include <vcl/syschild.hxx> +#include <vcl/tabctrl.hxx> +#include <vcl/tabpage.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/virdev.hxx> +#include <vcl/window.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/toolkit/group.hxx> +#include <vcl/toolkit/imgctrl.hxx> +#include <vcl/toolkit/morebtn.hxx> +#include <vcl/toolkit/roadmap.hxx> +#include <vcl/toolkit/spin.hxx> +#include <vcl/toolkit/tabdlg.hxx> +#include <vcl/toolkit/throbber.hxx> +#if HAVE_FEATURE_OPENGL +#include <vcl/opengl/OpenGLWrapper.hxx> +#endif +#include <awt/vclxspinbutton.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/processfactory.hxx> +#include <comphelper/profilezone.hxx> + +#include <helper/msgbox.hxx> +#include <helper/scrollabledialog.hxx> +#include <helper/unowrapper.hxx> + +#if defined(_WIN32) +#define SYSTEM_DEPENDENT_TYPE css::lang::SystemDependent::SYSTEM_WIN32 +#elif defined(MACOSX) +#define SYSTEM_DEPENDENT_TYPE css::lang::SystemDependent::SYSTEM_MAC +#elif defined(UNX) +#define SYSTEM_DEPENDENT_TYPE css::lang::SystemDependent::SYSTEM_XWINDOW +#endif + +void MessBox::ImplInitButtons() +{ + ButtonDialogFlags nOKFlags = ButtonDialogFlags::OK; + ButtonDialogFlags nCancelFlags = ButtonDialogFlags::Cancel; + ButtonDialogFlags nRetryFlags = ButtonDialogFlags::NONE; + ButtonDialogFlags nYesFlags = ButtonDialogFlags::NONE; + ButtonDialogFlags nNoFlags = ButtonDialogFlags::NONE; + + if ( mnMessBoxStyle & MessBoxStyle::OkCancel ) + { + if ( mnMessBoxStyle & MessBoxStyle::DefaultCancel ) + nCancelFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else // MessBoxStyle::DefaultOk + nOKFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + + AddButton( StandardButtonType::OK, RET_OK, nOKFlags ); + AddButton( StandardButtonType::Cancel, RET_CANCEL, nCancelFlags ); + } + else if ( mnMessBoxStyle & MessBoxStyle::YesNo ) + { + if ( mnMessBoxStyle & MessBoxStyle::DefaultYes ) + nYesFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else // MessBoxStyle::DefaultNo + nNoFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + nNoFlags |= ButtonDialogFlags::Cancel; + + AddButton( StandardButtonType::Yes, RET_YES, nYesFlags ); + AddButton( StandardButtonType::No, RET_NO, nNoFlags ); + } + else if ( mnMessBoxStyle & MessBoxStyle::YesNoCancel ) + { + if ( mnMessBoxStyle & MessBoxStyle::DefaultYes ) + nYesFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else if ( mnMessBoxStyle & MessBoxStyle::DefaultNo ) + nNoFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else + nCancelFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + + AddButton( StandardButtonType::Yes, RET_YES, nYesFlags ); + AddButton( StandardButtonType::No, RET_NO, nNoFlags ); + AddButton( StandardButtonType::Cancel, RET_CANCEL, nCancelFlags ); + } + else if ( mnMessBoxStyle & MessBoxStyle::RetryCancel ) + { + if ( mnMessBoxStyle & MessBoxStyle::DefaultCancel ) + nCancelFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else // MessBoxStyle::DefaultRetry + nRetryFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + + AddButton( StandardButtonType::Retry, RET_RETRY, nRetryFlags ); + AddButton( StandardButtonType::Cancel, RET_CANCEL, nCancelFlags ); + } + else if ( mnMessBoxStyle & MessBoxStyle::AbortRetryIgnore ) + { + ButtonDialogFlags nAbortFlags = ButtonDialogFlags::NONE; + ButtonDialogFlags nIgnoreFlags = ButtonDialogFlags::NONE; + + if ( mnMessBoxStyle & MessBoxStyle::DefaultCancel ) + nAbortFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else if ( mnMessBoxStyle & MessBoxStyle::DefaultRetry ) + nRetryFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + else if ( mnMessBoxStyle & MessBoxStyle::DefaultIgnore ) + nIgnoreFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + + AddButton( StandardButtonType::Abort, RET_CANCEL, nAbortFlags ); + AddButton( StandardButtonType::Retry, RET_RETRY, nRetryFlags ); + AddButton( StandardButtonType::Ignore, RET_IGNORE, nIgnoreFlags ); + } + else if ( mnMessBoxStyle & MessBoxStyle::Ok ) + { + nOKFlags |= ButtonDialogFlags::Default | ButtonDialogFlags::Focus; + + AddButton( StandardButtonType::OK, RET_OK, nOKFlags ); + } +} + +MessBox::MessBox(vcl::Window* pParent, MessBoxStyle nMessBoxStyle, WinBits nWinBits, + const OUString& rTitle, const OUString& rMessage) : + ButtonDialog( WindowType::MESSBOX ), + mbHelpBtn( false ), + mnMessBoxStyle( nMessBoxStyle ), + maMessText( rMessage ) +{ + ImplLOKNotifier(pParent); + ImplInitDialog(pParent, nWinBits | WB_MOVEABLE | WB_HORZ | WB_CENTER); + ImplInitButtons(); + + if ( !rTitle.isEmpty() ) + SetText( rTitle ); +} + +MessBox::~MessBox() +{ + disposeOnce(); +} + +void MessBox::dispose() +{ + mpVCLMultiLineEdit.disposeAndClear(); + mpFixedImage.disposeAndClear(); + ButtonDialog::dispose(); +} + +void MessBox::ImplPosControls() +{ + if ( !GetHelpId().isEmpty() ) + { + if ( !mbHelpBtn ) + { + AddButton( StandardButtonType::Help, RET_HELP, ButtonDialogFlags::Help, 3 ); + mbHelpBtn = true; + } + } + else + { + if ( mbHelpBtn ) + { + RemoveButton( RET_HELP ); + mbHelpBtn = false; + } + } + + TextRectInfo aTextInfo; + tools::Rectangle aRect( 0, 0, 30000, 30000 ); + tools::Rectangle aFormatRect; + Point aTextPos( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+IMPL_MSGBOX_OFFSET_EXTRA_Y ); + Size aImageSize; + Size aPageSize; + Size aMEditSize; + long nTitleWidth; + long nButtonSize = ImplGetButtonSize(); + long nMaxLineWidth; + long nWidth; + WinBits nWinStyle = WB_LEFT | WB_NOLABEL; + DrawTextFlags nTextStyle = DrawTextFlags::MultiLine | DrawTextFlags::Top | DrawTextFlags::Left; + + mpVCLMultiLineEdit.disposeAndClear(); + mpFixedImage.disposeAndClear(); + + // Clean up message text with tabs + OUString aMessText(maMessText.replaceAll("\t", " ")); + + //If window too small, we make dialog box be wider + long nMaxWidth = 630 * GetDPIScaleFactor(); + + // MessagBox should be at least as wide as to see the title + // Extra-Width for Close button, because Close button is set after this call + nTitleWidth = CalcTitleWidth(); + + nMaxWidth -= (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2); + + // for an image, get its size, create a suitable control and position it + aImageSize = maImage.GetSizePixel(); + if ( aImageSize.Width() ) + { + aImageSize.AdjustWidth(4 ); + aImageSize.AdjustHeight(4 ); + aTextPos.AdjustX(aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE ); + mpFixedImage = VclPtr<FixedImage>::Create( this ); + mpFixedImage->SetPosSizePixel( Point( IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_X, + IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_Y ), + aImageSize ); + mpFixedImage->SetImage( maImage ); + mpFixedImage->Show(); + nMaxWidth -= aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE; + } + else + aTextPos.AdjustX(IMPL_MSGBOX_OFFSET_EXTRA_X ); + + // Determine maximum line length without wordbreak + aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); + nMaxLineWidth = aFormatRect.GetWidth(); + nTextStyle |= DrawTextFlags::WordBreak; + + // Determine the width for text formatting + if ( nMaxLineWidth > 450 ) + nWidth = 450; + else if ( nMaxLineWidth > 300 ) + nWidth = nMaxLineWidth+5; + else + nWidth = 300; + + nWidth *= GetDPIScaleFactor(); + + if ( nButtonSize > nWidth ) + nWidth = nButtonSize-(aTextPos.X()-IMPL_DIALOG_OFFSET); + if ( nWidth > nMaxWidth ) + nWidth = nMaxWidth; + + aRect.SetRight( nWidth ); + aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); + if ( aTextInfo.GetMaxLineWidth() > nWidth ) + { + nWidth = aTextInfo.GetMaxLineWidth()+8; + aRect.SetRight( nWidth ); + aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); + } + + // get Style for VCLMultiLineEdit + aMEditSize.setWidth( aTextInfo.GetMaxLineWidth()+1 ); + aMEditSize.setHeight( aFormatRect.GetHeight() ); + aPageSize.setWidth( aImageSize.Width() ); + if ( aMEditSize.Height() < aImageSize.Height() ) + { + nWinStyle |= WB_VCENTER; + aPageSize.setHeight( aImageSize.Height() ); + aMEditSize.setHeight( aImageSize.Height() ); + } + else + { + nWinStyle |= WB_TOP; + aPageSize.setHeight( aMEditSize.Height() ); + } + if ( aImageSize.Width() ) + aPageSize.AdjustWidth(IMPL_SEP_MSGBOX_IMAGE ); + aPageSize.AdjustWidth((IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2) ); + aPageSize.AdjustWidth(aMEditSize.Width()+1 ); + aPageSize.AdjustHeight((IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2) ); + + if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH ) + aPageSize.setWidth( IMPL_MINSIZE_MSGBOX_WIDTH ); + if ( aPageSize.Width() < nTitleWidth ) + aPageSize.setWidth( nTitleWidth ); + + mpVCLMultiLineEdit = VclPtr<VclMultiLineEdit>::Create( this, nWinStyle ); + mpVCLMultiLineEdit->SetText( aMessText ); + mpVCLMultiLineEdit->SetPosSizePixel( aTextPos, aMEditSize ); + mpVCLMultiLineEdit->Show(); + mpVCLMultiLineEdit->SetPaintTransparent(true); + mpVCLMultiLineEdit->EnableCursor(false); + SetPageSizePixel( aPageSize ); +} + +void MessBox::StateChanged( StateChangedType nType ) +{ + if ( nType == StateChangedType::InitShow ) + { + ImplPosControls(); + } + ButtonDialog::StateChanged( nType ); +} + +Size MessBox::GetOptimalSize() const +{ + // FIXME: base me on the font size ? + return Size( 250, 100 ); +} + + +namespace { + +extern "C" typedef vcl::Window* (*FN_SvtCreateWindow)( + VCLXWindow** ppNewComp, + const css::awt::WindowDescriptor* pDescriptor, + vcl::Window* pParent, + WinBits nWinBits ); + +class Pause : public Idle +{ +public: + explicit Pause(sal_Int32 nPauseMilliseconds) : + Idle("pause"), + m_nPauseMilliseconds(nPauseMilliseconds) + { + SetPriority(TaskPriority::HIGHEST); + Start(); + } + + virtual void Invoke() override + { + SolarMutexGuard aSolarGuard; + osl::Thread::wait(std::chrono::milliseconds(m_nPauseMilliseconds)); + Stop(); + delete this; + } + + sal_Int32 m_nPauseMilliseconds; +}; + +class VCLXToolkitMutexHelper +{ +protected: + ::osl::Mutex maMutex; +}; + +class VCLXToolkit : public VCLXToolkitMutexHelper, + public cppu::WeakComponentImplHelper< + css::awt::XToolkitExperimental, + css::awt::XToolkitRobot, + css::lang::XServiceInfo > +{ + css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard; + css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxSelection; + + oslModule hSvToolsLib; + FN_SvtCreateWindow fnSvtCreateWindow; + + ::comphelper::OInterfaceContainerHelper2 m_aTopWindowListeners; + ::comphelper::OInterfaceContainerHelper2 m_aKeyHandlers; + ::comphelper::OInterfaceContainerHelper2 m_aFocusListeners; + ::Link<VclSimpleEvent&,void> m_aEventListenerLink; + ::Link<VclWindowEvent&,bool> m_aKeyListenerLink; + bool m_bEventListener; + bool m_bKeyListener; + + DECL_LINK(eventListenerHandler, ::VclSimpleEvent&, void); + + DECL_LINK(keyListenerHandler, ::VclWindowEvent&, bool); + + void callTopWindowListeners( + ::VclSimpleEvent const * pEvent, + void (SAL_CALL css::awt::XTopWindowListener::* pFn)( + css::lang::EventObject const &)); + + bool callKeyHandlers(::VclSimpleEvent const * pEvent, bool bPressed); + + void callFocusListeners(::VclSimpleEvent const * pEvent, bool bGained); + +protected: + ::osl::Mutex& GetMutex() { return maMutex; } + + virtual void SAL_CALL disposing() override; + + static vcl::Window* ImplCreateWindow( VCLXWindow** ppNewComp, const css::awt::WindowDescriptor& rDescriptor, vcl::Window* pParent, + WinBits nWinBits, MessBoxStyle nMessBoxStyle ); + css::uno::Reference< css::awt::XWindowPeer > ImplCreateWindow( const css::awt::WindowDescriptor& Descriptor, + MessBoxStyle nForceMessBoxStyle ); + +public: + + VCLXToolkit(); + + // css::awt::XToolkitExperimental + virtual void SAL_CALL processEventsToIdle() override; + + virtual sal_Int64 SAL_CALL getOpenGLBufferSwapCounter() override; + + virtual void SAL_CALL setDeterministicScheduling(sal_Bool bDeterministicMode) override; + + virtual void SAL_CALL pause(sal_Int32 nMilliseconds) override; + + virtual void SAL_CALL startRecording() override; + + virtual void SAL_CALL stopRecording() override; + + css::uno::Sequence< OUString > SAL_CALL getRecordingAndClear() override; + + // css::awt::XToolkit + css::uno::Reference< css::awt::XWindowPeer > SAL_CALL getDesktopWindow( ) override; + css::awt::Rectangle SAL_CALL getWorkArea( ) override; + css::uno::Reference< css::awt::XWindowPeer > SAL_CALL createWindow( const css::awt::WindowDescriptor& Descriptor ) override; + css::uno::Sequence< css::uno::Reference< css::awt::XWindowPeer > > SAL_CALL createWindows( const css::uno::Sequence< css::awt::WindowDescriptor >& Descriptors ) override; + css::uno::Reference< css::awt::XDevice > SAL_CALL createScreenCompatibleDevice( sal_Int32 Width, sal_Int32 Height ) override; + css::uno::Reference< css::awt::XRegion > SAL_CALL createRegion( ) override; + + // css::awt::XSystemChildFactory + css::uno::Reference< css::awt::XWindowPeer > SAL_CALL createSystemChild( const css::uno::Any& Parent, const css::uno::Sequence< sal_Int8 >& ProcessId, sal_Int16 SystemType ) override; + + // css::awt::XMessageBoxFactory + virtual css::uno::Reference< css::awt::XMessageBox > SAL_CALL createMessageBox( const css::uno::Reference< css::awt::XWindowPeer >& aParent, css::awt::MessageBoxType eType, ::sal_Int32 aButtons, const OUString& aTitle, const OUString& aMessage ) override; + + // css::awt::XDataTransfer + css::uno::Reference< css::datatransfer::dnd::XDragGestureRecognizer > SAL_CALL getDragGestureRecognizer( const css::uno::Reference< css::awt::XWindow >& window ) override; + css::uno::Reference< css::datatransfer::dnd::XDragSource > SAL_CALL getDragSource( const css::uno::Reference< css::awt::XWindow >& window ) override; + css::uno::Reference< css::datatransfer::dnd::XDropTarget > SAL_CALL getDropTarget( const css::uno::Reference< css::awt::XWindow >& window ) override; + css::uno::Reference< css::datatransfer::clipboard::XClipboard > SAL_CALL getClipboard( const OUString& clipboardName ) override; + + // css::lang::XServiceInfo + OUString SAL_CALL getImplementationName( ) override; + sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // css::awt::XExtendedToolkit: + + virtual ::sal_Int32 SAL_CALL getTopWindowCount() override; + + virtual css::uno::Reference< css::awt::XTopWindow > + SAL_CALL getTopWindow(::sal_Int32 nIndex) override; + + virtual css::uno::Reference< css::awt::XTopWindow > + SAL_CALL getActiveTopWindow() override; + + virtual void SAL_CALL addTopWindowListener( + css::uno::Reference< + css::awt::XTopWindowListener > const & rListener) override; + + virtual void SAL_CALL removeTopWindowListener( + css::uno::Reference< + css::awt::XTopWindowListener > const & rListener) override; + + virtual void SAL_CALL addKeyHandler( + css::uno::Reference< + css::awt::XKeyHandler > const & rHandler) override; + + virtual void SAL_CALL removeKeyHandler( + css::uno::Reference< + css::awt::XKeyHandler > const & rHandler) override; + + virtual void SAL_CALL addFocusListener( + css::uno::Reference< + css::awt::XFocusListener > const & rListener) override; + + virtual void SAL_CALL removeFocusListener( + css::uno::Reference< + css::awt::XFocusListener > const & rListener) override; + + virtual void SAL_CALL fireFocusGained( + css::uno::Reference< + css::uno::XInterface > const & source) override; + + virtual void SAL_CALL fireFocusLost( + css::uno::Reference< + css::uno::XInterface > const & source) override; + + // css::awt::XReschedule: + virtual void SAL_CALL reschedule() override; + + // css:awt:XToolkitRobot + virtual void SAL_CALL keyPress( const css::awt::KeyEvent & aKeyEvent ) override; + + virtual void SAL_CALL keyRelease( const css::awt::KeyEvent & aKeyEvent ) override; + + virtual void SAL_CALL mousePress( const css::awt::MouseEvent & aMouseEvent ) override; + + virtual void SAL_CALL mouseRelease( const css::awt::MouseEvent & aMouseEvent ) override; + + virtual void SAL_CALL mouseMove( const css::awt::MouseEvent & aMouseEvent ) override; + +}; + +std::pair<WinBits,MessBoxStyle> ImplGetWinBits( sal_uInt32 nComponentAttribs, WindowType nCompType ) +{ + WinBits nWinBits = 0; + MessBoxStyle nStyle = MessBoxStyle::NONE; + + bool bMessBox = false; + if ( ( nCompType == WindowType::INFOBOX ) || + ( nCompType == WindowType::MESSBOX ) || + ( nCompType == WindowType::QUERYBOX ) || + ( nCompType == WindowType::WARNINGBOX ) || + ( nCompType == WindowType::ERRORBOX ) ) + { + bMessBox = true; + } + + bool bDecoratedWindow = false; + if ( bMessBox + || ( nCompType == WindowType::DIALOG ) + || ( nCompType == WindowType::MODELESSDIALOG ) + || ( nCompType == WindowType::MODALDIALOG ) + || ( nCompType == WindowType::DOCKINGWINDOW ) + || ( nCompType == WindowType::TABDIALOG ) + || ( nCompType == WindowType::BUTTONDIALOG ) + || ( nCompType == WindowType::SYSTEMCHILDWINDOW ) + ) + { + bDecoratedWindow = true; + } + + if( nComponentAttribs & css::awt::WindowAttribute::BORDER ) + nWinBits |= WB_BORDER; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::NOBORDER ) + nWinBits |= WB_NOBORDER; + if( nComponentAttribs & css::awt::WindowAttribute::SIZEABLE ) + nWinBits |= WB_SIZEABLE; + if( nComponentAttribs & css::awt::WindowAttribute::MOVEABLE ) + nWinBits |= WB_MOVEABLE; + if( nComponentAttribs & css::awt::WindowAttribute::CLOSEABLE ) + nWinBits |= WB_CLOSEABLE; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::HSCROLL ) + nWinBits |= WB_HSCROLL; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::VSCROLL ) + nWinBits |= WB_VSCROLL; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::LEFT ) + nWinBits |= WB_LEFT; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::CENTER ) + nWinBits |= WB_CENTER; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::RIGHT ) + nWinBits |= WB_RIGHT; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::SPIN ) + nWinBits |= WB_SPIN; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::SORT ) + nWinBits |= WB_SORT; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DROPDOWN ) + nWinBits |= WB_DROPDOWN; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DEFBUTTON ) + nWinBits |= WB_DEFBUTTON; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::READONLY ) + nWinBits |= WB_READONLY; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::CLIPCHILDREN ) + nWinBits |= WB_CLIPCHILDREN; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::GROUP ) + nWinBits |= WB_GROUP; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::NOLABEL ) //added for issue79712 + nWinBits |= WB_NOLABEL; + + // These bits are not unique + if ( bMessBox ) + { + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::OK ) + nStyle |= MessBoxStyle::Ok; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::OK_CANCEL ) + nStyle |= MessBoxStyle::OkCancel; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::YES_NO ) + nStyle |= MessBoxStyle::YesNo; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::YES_NO_CANCEL ) + nStyle |= MessBoxStyle::YesNoCancel; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::RETRY_CANCEL ) + nStyle |= MessBoxStyle::RetryCancel; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DEF_OK ) + nStyle |= MessBoxStyle::DefaultOk; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DEF_CANCEL ) + nStyle |= MessBoxStyle::DefaultCancel; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DEF_RETRY ) + nStyle |= MessBoxStyle::DefaultRetry; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DEF_YES ) + nStyle |= MessBoxStyle::DefaultYes; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::DEF_NO ) + nStyle |= MessBoxStyle::DefaultNo; + } + if ( nCompType == WindowType::MULTILINEEDIT || nCompType == WindowType::DIALOG || nCompType == WindowType::GROUPBOX ) + { + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::AUTOHSCROLL ) + nWinBits |= WB_AUTOHSCROLL; + if( nComponentAttribs & css::awt::VclWindowPeerAttribute::AUTOVSCROLL ) + nWinBits |= WB_AUTOVSCROLL; + } + + + if ( bDecoratedWindow ) + { + if( nComponentAttribs & css::awt::WindowAttribute::NODECORATION ) + { + // No decoration removes several window attributes and must + // set WB_NOBORDER! + nWinBits &= ~WB_BORDER; + nWinBits &= ~WB_SIZEABLE; + nWinBits &= ~WB_MOVEABLE; + nWinBits &= ~WB_CLOSEABLE; + nWinBits |= WB_NOBORDER; + } + } + + return { nWinBits, nStyle }; +} + +struct ComponentInfo +{ + OUStringLiteral sName; + WindowType nWinType; +}; + +static ComponentInfo const aComponentInfos [] = +{ + { OUStringLiteral("animatedimages"), WindowType::CONTROL }, + { OUStringLiteral("buttondialog"), WindowType::BUTTONDIALOG }, + { OUStringLiteral("cancelbutton"), WindowType::CANCELBUTTON }, + { OUStringLiteral("checkbox"), WindowType::CHECKBOX }, + { OUStringLiteral("combobox"), WindowType::COMBOBOX }, + { OUStringLiteral("control"), WindowType::CONTROL }, + { OUStringLiteral("currencybox"), WindowType::CURRENCYBOX }, + { OUStringLiteral("currencyfield"), WindowType::CURRENCYFIELD }, + { OUStringLiteral("datebox"), WindowType::DATEBOX }, + { OUStringLiteral("datefield"), WindowType::DATEFIELD }, + { OUStringLiteral("dialog"), WindowType::DIALOG }, + { OUStringLiteral("dockingarea"), WindowType::DOCKINGAREA }, + { OUStringLiteral("dockingwindow"), WindowType::DOCKINGWINDOW }, + { OUStringLiteral("edit"), WindowType::EDIT }, + { OUStringLiteral("errorbox"), WindowType::ERRORBOX }, + { OUStringLiteral("filecontrol"), WindowType::CONTROL }, + { OUStringLiteral("fixedbitmap"), WindowType::FIXEDBITMAP }, + { OUStringLiteral("fixedhyperlink"), WindowType::CONTROL }, + { OUStringLiteral("fixedimage"), WindowType::FIXEDIMAGE }, + { OUStringLiteral("fixedline"), WindowType::FIXEDLINE }, + { OUStringLiteral("fixedtext"), WindowType::FIXEDTEXT }, + { OUStringLiteral("floatingwindow"), WindowType::FLOATINGWINDOW }, + { OUStringLiteral("formattedfield"), WindowType::CONTROL }, + { OUStringLiteral("frame"), WindowType::GROUPBOX }, + { OUStringLiteral("framewindow"), WindowType::TOOLKIT_FRAMEWINDOW }, + { OUStringLiteral("groupbox"), WindowType::GROUPBOX }, + { OUStringLiteral("helpbutton"), WindowType::HELPBUTTON }, + { OUStringLiteral("imagebutton"), WindowType::IMAGEBUTTON }, + { OUStringLiteral("infobox"), WindowType::INFOBOX }, + { OUStringLiteral("listbox"), WindowType::LISTBOX }, + { OUStringLiteral("longcurrencybox"), WindowType::LONGCURRENCYBOX }, + { OUStringLiteral("longcurrencyfield"), WindowType::CONTROL }, + { OUStringLiteral("menubutton"), WindowType::MENUBUTTON }, + { OUStringLiteral("messbox"), WindowType::MESSBOX }, + { OUStringLiteral("metricbox"), WindowType::METRICBOX }, + { OUStringLiteral("metricfield"), WindowType::METRICFIELD }, + { OUStringLiteral("modaldialog"), WindowType::MODALDIALOG }, + { OUStringLiteral("modelessdialog"), WindowType::MODELESSDIALOG }, + { OUStringLiteral("morebutton"), WindowType::MOREBUTTON }, + { OUStringLiteral("multilineedit"), WindowType::MULTILINEEDIT }, + { OUStringLiteral("multilistbox"), WindowType::MULTILISTBOX }, + { OUStringLiteral("numericbox"), WindowType::NUMERICBOX }, + { OUStringLiteral("numericfield"), WindowType::CONTROL }, + { OUStringLiteral("okbutton"), WindowType::OKBUTTON }, + { OUStringLiteral("patternbox"), WindowType::PATTERNBOX }, + { OUStringLiteral("patternfield"), WindowType::PATTERNFIELD }, + { OUStringLiteral("progressbar"), WindowType::CONTROL }, + { OUStringLiteral("pushbutton"), WindowType::PUSHBUTTON }, + { OUStringLiteral("querybox"), WindowType::QUERYBOX }, + { OUStringLiteral("radiobutton"), WindowType::RADIOBUTTON }, + { OUStringLiteral("roadmap"), WindowType::CONTROL }, + { OUStringLiteral("scrollbar"), WindowType::SCROLLBAR }, + { OUStringLiteral("scrollbarbox"), WindowType::SCROLLBARBOX }, + { OUStringLiteral("spinbutton"), WindowType::SPINBUTTON }, + { OUStringLiteral("spinfield"), WindowType::SPINFIELD }, + { OUStringLiteral("splitter"), WindowType::SPLITTER }, + { OUStringLiteral("splitwindow"), WindowType::SPLITWINDOW }, + { OUStringLiteral("statusbar"), WindowType::STATUSBAR }, + { OUStringLiteral("systemchildwindow"), WindowType::TOOLKIT_SYSTEMCHILDWINDOW }, + { OUStringLiteral("tabcontrol"), WindowType::TABCONTROL }, + { OUStringLiteral("tabdialog"), WindowType::TABDIALOG }, + { OUStringLiteral("tabpage"), WindowType::TABPAGE }, + { OUStringLiteral("tabpagecontainer"), WindowType::CONTROL }, + { OUStringLiteral("tabpagemodel"), WindowType::TABPAGE }, + { OUStringLiteral("timebox"), WindowType::TIMEBOX }, + { OUStringLiteral("timefield"), WindowType::TIMEFIELD }, + { OUStringLiteral("toolbox"), WindowType::TOOLBOX }, + { OUStringLiteral("tree"), WindowType::CONTROL }, + { OUStringLiteral("tristatebox"), WindowType::TRISTATEBOX }, + { OUStringLiteral("warningbox"), WindowType::WARNINGBOX }, + { OUStringLiteral("window"), WindowType::WINDOW }, + { OUStringLiteral("workwindow"), WindowType::WORKWINDOW } +}; + +bool ComponentInfoFindCompare( const ComponentInfo & lhs, const OUString & s) +{ + return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(s.pData->buffer, s.pData->length, + lhs.sName.data, lhs.sName.size) > 0; +} + +WindowType ImplGetComponentType( const OUString& rServiceName ) +{ + static bool bSorted = false; + if( !bSorted ) + { + assert( std::is_sorted( std::begin(aComponentInfos), std::end(aComponentInfos), + [](const ComponentInfo & lhs, const ComponentInfo & rhs) { + return + rtl_str_compare_WithLength( + lhs.sName.data, lhs.sName.size, rhs.sName.data, rhs.sName.size) + < 0; + } ) ); + bSorted = true; + } + + OUString sSearch; + if ( !rServiceName.isEmpty() ) + sSearch = rServiceName; + else + sSearch = "window"; + + auto it = std::lower_bound( std::begin(aComponentInfos), std::end(aComponentInfos), sSearch, + ComponentInfoFindCompare ); + if (it != std::end(aComponentInfos) && + rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(sSearch.pData->buffer, sSearch.pData->length, it->sName.data, it->sName.size) == 0) + return it->nWinType; + return WindowType::NONE; +} + +struct MessageBoxTypeInfo +{ + css::awt::MessageBoxType eType; + const char *pName; + sal_Int32 nLen; +}; + +static const MessageBoxTypeInfo aMessageBoxTypeInfo[] = +{ + { css::awt::MessageBoxType_MESSAGEBOX, RTL_CONSTASCII_STRINGPARAM("messbox") }, + { css::awt::MessageBoxType_INFOBOX, RTL_CONSTASCII_STRINGPARAM("infobox") }, + { css::awt::MessageBoxType_WARNINGBOX, RTL_CONSTASCII_STRINGPARAM("warningbox") }, + { css::awt::MessageBoxType_ERRORBOX, RTL_CONSTASCII_STRINGPARAM("errorbox") }, + { css::awt::MessageBoxType_QUERYBOX, RTL_CONSTASCII_STRINGPARAM("querybox") }, + { css::awt::MessageBoxType::MessageBoxType_MAKE_FIXED_SIZE, nullptr, 0 } +}; + +bool lcl_convertMessageBoxType( + OUString &sType, + css::awt::MessageBoxType eType ) +{ + const MessageBoxTypeInfo *pMap = aMessageBoxTypeInfo; + css::awt::MessageBoxType eVal = css::awt::MessageBoxType::MessageBoxType_MAKE_FIXED_SIZE; + + while ( pMap->pName ) + { + if ( pMap->eType == eType ) + { + eVal = eType; + sType = OUString( pMap->pName, pMap->nLen, RTL_TEXTENCODING_ASCII_US ); + break; + } + pMap++; + } + + return ( eVal != css::awt::MessageBoxType::MessageBoxType_MAKE_FIXED_SIZE ); +} + +#ifndef IOS + +static sal_Int32 nVCLToolkitInstanceCount = 0; +static bool bInitedByVCLToolkit = false; + +osl::Mutex & getInitMutex() +{ + static osl::Mutex aMutex; + return aMutex; +} + +osl::Condition & getInitCondition() +{ + static osl::Condition aCondition; + return aCondition; +} + +extern "C" +{ +static void ToolkitWorkerFunction( void* pArgs ) +{ + osl_setThreadName("VCLXToolkit VCL main thread"); + + css::uno::Reference<css::lang::XMultiServiceFactory> xServiceManager; + try + { + xServiceManager = ::comphelper::getProcessServiceFactory(); + } + catch (const css::uno::DeploymentException&) + { + } + if (!xServiceManager.is()) + { + css::uno::Reference<css::uno::XComponentContext> xContext = + ::cppu::defaultBootstrap_InitialComponentContext(); + + xServiceManager.set( xContext->getServiceManager(), css::uno::UNO_QUERY_THROW ); + // set global process service factory used by unotools config helpers + ::comphelper::setProcessServiceFactory( xServiceManager ); + } + + VCLXToolkit * pTk = static_cast<VCLXToolkit *>(pArgs); + bInitedByVCLToolkit = !IsVCLInit() && InitVCL(); + if( bInitedByVCLToolkit ) + { + UnoWrapper* pUnoWrapper = new UnoWrapper( pTk ); + UnoWrapperBase::SetUnoWrapper( pUnoWrapper ); + } + getInitCondition().set(); + if( bInitedByVCLToolkit ) + { + { + SolarMutexGuard aGuard; + Application::Execute(); + } + try + { + pTk->dispose(); + } + catch( css::uno::Exception & ) + { + } + DeInitVCL(); + } + else + { + // having the thread join itself is pretty stupid. + // but we can't get the osl_Thread to destroy here so just leak it. + } +} +} + +#endif + +// constructor, which might initialize VCL +VCLXToolkit::VCLXToolkit(): + cppu::WeakComponentImplHelper< + css::awt::XToolkitExperimental, + css::awt::XToolkitRobot, + css::lang::XServiceInfo>( GetMutex() ), + m_aTopWindowListeners(rBHelper.rMutex), + m_aKeyHandlers(rBHelper.rMutex), + m_aFocusListeners(rBHelper.rMutex), + m_aEventListenerLink(LINK(this, VCLXToolkit, eventListenerHandler)), + m_aKeyListenerLink(LINK(this, VCLXToolkit, keyListenerHandler)), + m_bEventListener(false), + m_bKeyListener(false) +{ + hSvToolsLib = nullptr; + fnSvtCreateWindow = nullptr; + +#ifndef IOS + osl::Guard< osl::Mutex > aGuard( getInitMutex() ); + nVCLToolkitInstanceCount++; + if( ( nVCLToolkitInstanceCount == 1 ) && ( !Application::IsInMain() ) ) + { + // setup execute thread + CreateMainLoopThread( ToolkitWorkerFunction, this ); + getInitCondition().wait(); + } +#endif +} + +void SAL_CALL VCLXToolkit::disposing() +{ +#ifndef DISABLE_DYNLOADING + if ( hSvToolsLib ) + { + osl_unloadModule( hSvToolsLib ); + hSvToolsLib = nullptr; + fnSvtCreateWindow = nullptr; + } +#endif + +#ifndef IOS + { + osl::Guard< osl::Mutex > aGuard( getInitMutex() ); + if( --nVCLToolkitInstanceCount == 0 ) + { + if( bInitedByVCLToolkit ) + { + Application::Quit(); + JoinMainLoopThread(); + bInitedByVCLToolkit = false; + } + } + } +#endif + if (m_bEventListener) + { + ::Application::RemoveEventListener(m_aEventListenerLink); + m_bEventListener = false; + } + if (m_bKeyListener) + { + ::Application::RemoveKeyListener(m_aKeyListenerLink); + m_bKeyListener = false; + } + css::lang::EventObject aEvent( + static_cast< ::cppu::OWeakObject * >(this)); + m_aTopWindowListeners.disposeAndClear(aEvent); + m_aKeyHandlers.disposeAndClear(aEvent); + m_aFocusListeners.disposeAndClear(aEvent); +} + + +css::uno::Reference< css::awt::XWindowPeer > VCLXToolkit::getDesktopWindow( ) +{ + css::uno::Reference< css::awt::XWindowPeer > xRef; + // 07/00: AppWindow doesn't exist anymore... + return xRef; +} + +css::awt::Rectangle VCLXToolkit::getWorkArea( ) +{ + sal_Int32 nDisplay = Application::GetDisplayBuiltInScreen(); + tools::Rectangle aWorkRect = Application::GetScreenPosSizePixel( nDisplay ); + css::awt::Rectangle aNotherRect; + aNotherRect.X = aWorkRect.getX(); + aNotherRect.Y = aWorkRect.getY(); + aNotherRect.Width = aWorkRect.getWidth(); + aNotherRect.Height = aWorkRect.getHeight(); + return aNotherRect; +} + +css::uno::Reference< css::awt::XWindowPeer > VCLXToolkit::createWindow( const css::awt::WindowDescriptor& rDescriptor ) +{ + return ImplCreateWindow( rDescriptor, MessBoxStyle::NONE ); +} + +css::uno::Reference< css::awt::XDevice > VCLXToolkit::createScreenCompatibleDevice( sal_Int32 Width, sal_Int32 Height ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Reference< css::awt::XDevice > xRef; + VCLXVirtualDevice* pVDev = new VCLXVirtualDevice; + + SolarMutexGuard aSolarGuard; + + VclPtrInstance<VirtualDevice> pV; + pV->SetOutputSizePixel( Size( Width, Height ) ); + pVDev->SetVirtualDevice( pV ); + + xRef = pVDev; + return xRef; +} + +css::uno::Reference< css::awt::XRegion > VCLXToolkit::createRegion( ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + css::uno::Reference< css::awt::XRegion > xRef = new VCLXRegion; + return xRef; +} + +class InfoBox : public MessBox +{ +public: + InfoBox(vcl::Window* pParent, const OUString& rMessage) + : MessBox(pParent, MessBoxStyle::Ok | MessBoxStyle::DefaultOk, 0, OUString(), rMessage) + { + // Default Text is the display title from the application + if (GetText().isEmpty()) + SetText(GetStandardInfoBoxText()); + SetImage(GetStandardInfoBoxImage()); + } +}; + +class ErrorBox : public MessBox +{ +public: + ErrorBox(vcl::Window* pParent, MessBoxStyle nStyle, WinBits nWinBits, const OUString& rMessage) + : MessBox(pParent, nStyle, nWinBits, OUString(), rMessage) + { + // Default Text is the display title from the application + if (GetText().isEmpty()) + SetText(GetStandardErrorBoxText()); + SetImage(GetStandardErrorBoxImage()); + } +}; + +class QueryBox : public MessBox +{ +public: + QueryBox(vcl::Window* pParent, MessBoxStyle nStyle, WinBits nWinBits, const OUString& rMessage) + : MessBox(pParent, nStyle, nWinBits, OUString(), rMessage) + { + // Default Text is the display title from the application + if (GetText().isEmpty()) + SetText(GetStandardQueryBoxText()); + SetImage(GetStandardQueryBoxImage()); + } +}; + +class WarningBox : public MessBox +{ +public: + WarningBox(vcl::Window* pParent, MessBoxStyle nStyle, WinBits nWinBits, const OUString& rMessage) + : MessBox(pParent, nStyle, nWinBits, OUString(), rMessage) + { + // Default Text is the display title from the application + if (GetText().isEmpty()) + SetText(GetStandardWarningBoxText()); + SetImage(GetStandardWarningBoxImage()); + } +}; + + +struct RMItemData +{ + bool b_Enabled; + sal_Int32 n_ID; + OUString Label; +}; + +typedef ::cppu::ImplInheritanceHelper < VCLXGraphicControl + , css::container::XContainerListener + , css::beans::XPropertyChangeListener + , css::awt::XItemEventBroadcaster + > SVTXRoadmap_Base; +class SVTXRoadmap final : public SVTXRoadmap_Base +{ +public: + SVTXRoadmap(); + + void SAL_CALL disposing( const css::lang::EventObject& Source ) override { VCLXWindow::disposing( Source ); } + + // css::awt::XVclWindowPeer + void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override; + + css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override; + + // XContainerListener + void SAL_CALL elementInserted( const css::container::ContainerEvent& rEvent ) override; + void SAL_CALL elementRemoved( const css::container::ContainerEvent& rEvent ) override; + void SAL_CALL elementReplaced( const css::container::ContainerEvent& rEvent ) override; + + // XItemEventBroadcaster + virtual void SAL_CALL addItemListener( const css::uno::Reference< css::awt::XItemListener >& l ) override; + virtual void SAL_CALL removeItemListener( const css::uno::Reference< css::awt::XItemListener >& l ) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + +private: + + // VCLXGraphicControl overridables + virtual void ImplSetNewImage() override; + + static void ImplGetPropertyIds( std::vector< sal_uInt16 > &aIds ); + virtual void GetPropertyIds( std::vector< sal_uInt16 > &aIds ) override { return ImplGetPropertyIds( aIds ); } + + static RMItemData GetRMItemData( const css::container::ContainerEvent& _rEvent ); + + virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override; + + virtual ~SVTXRoadmap() override; + + ItemListenerMultiplexer maItemListeners; +}; + + + + +SVTXRoadmap::SVTXRoadmap() : maItemListeners( *this ) +{ +} + +SVTXRoadmap::~SVTXRoadmap() +{ +} + +void SVTXRoadmap::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) +{ + switch ( rVclWindowEvent.GetId() ) + { + case VclEventId::RoadmapItemSelected: + { + SolarMutexGuard aGuard; + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( pField ) + { + sal_Int16 CurItemID = pField->GetCurrentRoadmapItemID(); + css::awt::ItemEvent aEvent; + aEvent.Selected = CurItemID; + aEvent.Highlighted = CurItemID; + aEvent.ItemId = CurItemID; + maItemListeners.itemStateChanged( aEvent ); + } + } + break; + default: + SVTXRoadmap_Base::ProcessWindowEvent( rVclWindowEvent ); + break; + } +} + +void SVTXRoadmap::propertyChange( const css::beans::PropertyChangeEvent& evt ) +{ + SolarMutexGuard aGuard; + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( !pField ) + return; + + css::uno::Reference< css::uno::XInterface > xRoadmapItem = evt.Source; + sal_Int32 nID = 0; + css::uno::Reference< css::beans::XPropertySet > xPropertySet( xRoadmapItem, css::uno::UNO_QUERY ); + css::uno::Any aValue = xPropertySet->getPropertyValue("ID"); + aValue >>= nID; + + OUString sPropertyName = evt.PropertyName; + if ( sPropertyName == "Enabled" ) + { + bool bEnable = false; + evt.NewValue >>= bEnable; + pField->EnableRoadmapItem( static_cast<vcl::RoadmapTypes::ItemId>(nID) , bEnable ); + } + else if ( sPropertyName == "Label" ) + { + OUString sLabel; + evt.NewValue >>= sLabel; + pField->ChangeRoadmapItemLabel( static_cast<vcl::RoadmapTypes::ItemId>(nID) , sLabel ); + } + else if ( sPropertyName == "ID" ) + { + sal_Int32 nNewID = 0; + evt.NewValue >>= nNewID; + evt.OldValue >>= nID; + pField->ChangeRoadmapItemID( static_cast<vcl::RoadmapTypes::ItemId>(nID), static_cast<vcl::RoadmapTypes::ItemId>(nNewID) ); + } +// else + // TODO handle Interactive appropriately +} + +void SVTXRoadmap::addItemListener( const css::uno::Reference< css::awt::XItemListener >& l ) +{ + maItemListeners.addInterface( l ); +} + +void SVTXRoadmap::removeItemListener( const css::uno::Reference< css::awt::XItemListener >& l ) +{ + maItemListeners.removeInterface( l ); +} + +RMItemData SVTXRoadmap::GetRMItemData( const css::container::ContainerEvent& _rEvent ) +{ + RMItemData aCurRMItemData; + css::uno::Reference< css::uno::XInterface > xRoadmapItem; + _rEvent.Element >>= xRoadmapItem; + css::uno::Reference< css::beans::XPropertySet > xPropertySet( xRoadmapItem, css::uno::UNO_QUERY ); + if ( xPropertySet.is() ) + { + css::uno::Any aValue = xPropertySet->getPropertyValue("Label"); + aValue >>= aCurRMItemData.Label; + aValue = xPropertySet->getPropertyValue("ID"); + aValue >>= aCurRMItemData.n_ID; + aValue = xPropertySet->getPropertyValue("Enabled"); + aValue >>= aCurRMItemData.b_Enabled; + } + else + { + aCurRMItemData.b_Enabled = false; + aCurRMItemData.n_ID = 0; + } + return aCurRMItemData; +} + +void SVTXRoadmap::elementInserted( const css::container::ContainerEvent& _rEvent ) +{ + SolarMutexGuard aGuard; + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( pField ) + { + RMItemData CurItemData = GetRMItemData( _rEvent ); + sal_Int32 InsertIndex = 0; + _rEvent.Accessor >>= InsertIndex; + pField->InsertRoadmapItem( InsertIndex, CurItemData.Label, static_cast<vcl::RoadmapTypes::ItemId>(CurItemData.n_ID), CurItemData.b_Enabled ); + } +} + +void SVTXRoadmap::elementRemoved( const css::container::ContainerEvent& _rEvent ) +{ + SolarMutexGuard aGuard; + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( pField ) + { + sal_Int32 DelIndex = 0; + _rEvent.Accessor >>= DelIndex; + pField->DeleteRoadmapItem(DelIndex); + } +} + +void SVTXRoadmap::elementReplaced( const css::container::ContainerEvent& _rEvent ) +{ + SolarMutexGuard aGuard; + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( pField ) + { + RMItemData CurItemData = GetRMItemData( _rEvent ); + sal_Int32 ReplaceIndex = 0; + _rEvent.Accessor >>= ReplaceIndex; + pField->ReplaceRoadmapItem( ReplaceIndex, CurItemData.Label, static_cast<vcl::RoadmapTypes::ItemId>(CurItemData.n_ID), CurItemData.b_Enabled ); + } +} + +void SVTXRoadmap::setProperty( const OUString& PropertyName, const css::uno::Any& Value) +{ + SolarMutexGuard aGuard; + + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( pField ) + { + sal_uInt16 nPropType = GetPropertyId( PropertyName ); + switch (nPropType) + { + case BASEPROPERTY_COMPLETE: + { + bool b = false; + Value >>= b; + pField->SetRoadmapComplete( b); + } + break; + + case BASEPROPERTY_ACTIVATED: + { + bool b = false; + Value >>= b; + pField->SetRoadmapInteractive( b); + } + break; + + case BASEPROPERTY_CURRENTITEMID: + { + sal_Int32 nId = 0; + Value >>= nId; + pField->SelectRoadmapItemByID( static_cast<vcl::RoadmapTypes::ItemId>(nId) ); + } + break; + + case BASEPROPERTY_TEXT: + { + OUString aStr; + Value >>= aStr; + pField->SetText( aStr ); + pField->Invalidate(); + } + break; + + default: + SVTXRoadmap_Base::setProperty( PropertyName, Value ); + break; + } + + } + else + SVTXRoadmap_Base::setProperty( PropertyName, Value ); +} + + +css::uno::Any SVTXRoadmap::getProperty( const OUString& PropertyName ) +{ + SolarMutexGuard aGuard; + + css::uno::Any aReturn; + + VclPtr<::vcl::ORoadmap> pField = GetAs< vcl::ORoadmap >(); + if ( pField ) + { + sal_uInt16 nPropType = GetPropertyId( PropertyName ); + switch (nPropType) + { + case BASEPROPERTY_COMPLETE: + aReturn <<= pField->IsRoadmapComplete(); + break; + case BASEPROPERTY_ACTIVATED: + aReturn <<= pField->IsRoadmapInteractive(); + break; + case BASEPROPERTY_CURRENTITEMID: + aReturn <<= pField->GetCurrentRoadmapItemID(); + break; + default: + aReturn = SVTXRoadmap_Base::getProperty(PropertyName); + break; + } + } + return aReturn; +} + +void SVTXRoadmap::ImplSetNewImage() +{ + OSL_PRECOND( GetWindow(), "SVTXRoadmap::ImplSetNewImage: window is required to be not-NULL!" ); + VclPtr< ::vcl::ORoadmap > pButton = GetAs< ::vcl::ORoadmap >(); + pButton->SetRoadmapBitmap( GetImage().GetBitmapEx() ); +} + +void SVTXRoadmap::ImplGetPropertyIds( std::vector< sal_uInt16 > &rIds ) +{ + PushPropertyIds( rIds, + BASEPROPERTY_COMPLETE, + BASEPROPERTY_ACTIVATED, + BASEPROPERTY_CURRENTITEMID, + BASEPROPERTY_TEXT, + 0); + VCLXWindow::ImplGetPropertyIds( rIds, true ); + VCLXGraphicControl::ImplGetPropertyIds( rIds ); +} + + + + +vcl::Window* VCLXToolkit::ImplCreateWindow( VCLXWindow** ppNewComp, + const css::awt::WindowDescriptor& rDescriptor, + vcl::Window* pParent, WinBits nWinBits, MessBoxStyle nMessBoxStyle ) +{ + OUString aServiceName = rDescriptor.WindowServiceName.toAsciiLowerCase(); + + VclPtr<vcl::Window> pNewWindow; + WindowType nType = ImplGetComponentType( aServiceName ); + bool bFrameControl = false; + if ( aServiceName == "frame" ) + bFrameControl = true; + if ( aServiceName == "tabcontrolnotabs" ) + { + nWinBits |= WB_NOBORDER; + nType = ImplGetComponentType( "tabcontrol" ); + } + if ( !pParent ) + { + // If the component needs a parent, then return NULL, + // some time later css::uno::Exception... + bool bException = true; + if ( ( nType == WindowType::DIALOG ) + || ( nType == WindowType::MODALDIALOG ) + || ( nType == WindowType::MODELESSDIALOG ) + || ( nType == WindowType::MESSBOX ) + || ( nType == WindowType::INFOBOX ) + || ( nType == WindowType::WARNINGBOX ) + || ( nType == WindowType::ERRORBOX ) + || ( nType == WindowType::QUERYBOX ) + ) + bException = false; + else if ( ( nType == WindowType::WINDOW ) || + ( nType == WindowType::WORKWINDOW ) || + ( nType == WindowType::TOOLKIT_FRAMEWINDOW ) ) + { + if ( rDescriptor.Type == css::awt::WindowClass_TOP ) + bException = false; + } + + if ( bException ) + { + *ppNewComp = nullptr; + return nullptr; + } + } + + if ( nType != WindowType::NONE ) + { + SolarMutexGuard aVclGuard; + switch ( nType ) + { + case WindowType::CANCELBUTTON: + pNewWindow = VclPtr<CancelButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::CHECKBOX: + pNewWindow = VclPtr<CheckBox>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXCheckBox; + break; + case WindowType::COMBOBOX: + pNewWindow = VclPtr<ComboBox>::Create( pParent, nWinBits|WB_AUTOHSCROLL ); + static_cast<ComboBox*>(pNewWindow.get())->EnableAutoSize( false ); + *ppNewComp = new VCLXComboBox; + break; + case WindowType::CURRENCYBOX: + pNewWindow = VclPtr<CurrencyBox>::Create( pParent, nWinBits ); + break; + case WindowType::CURRENCYFIELD: + pNewWindow = VclPtr<CurrencyField>::Create( pParent, nWinBits ); + static_cast<CurrencyField*>(pNewWindow.get())->EnableEmptyFieldValue( true ); + *ppNewComp = new VCLXNumericField; + static_cast<VCLXFormattedSpinField*>(*ppNewComp)->SetFormatter( static_cast<FormatterBase*>(static_cast<CurrencyField*>(pNewWindow.get())) ); + break; + case WindowType::DATEBOX: + pNewWindow = VclPtr<DateBox>::Create( pParent, nWinBits ); + break; + case WindowType::DATEFIELD: + pNewWindow = VclPtr<DateField>::Create( pParent, nWinBits ); + static_cast<DateField*>(pNewWindow.get())->EnableEmptyFieldValue( true ); + *ppNewComp = new VCLXDateField; + static_cast<VCLXFormattedSpinField*>(*ppNewComp)->SetFormatter( static_cast<FormatterBase*>(static_cast<DateField*>(pNewWindow.get())) ); + break; + case WindowType::DOCKINGAREA: + pNewWindow = VclPtr<DockingAreaWindow>::Create( pParent ); + break; + case WindowType::MULTILINEEDIT: + case WindowType::EDIT: + pNewWindow = VclPtr<Edit>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXEdit; + break; + case WindowType::ERRORBOX: + pNewWindow = VclPtr<ErrorBox>::Create( pParent, nMessBoxStyle, nWinBits, OUString() ); + *ppNewComp = new VCLXMessageBox; + break; + case WindowType::FIXEDBITMAP: + pNewWindow = VclPtr<FixedBitmap>::Create( pParent, nWinBits ); + break; + case WindowType::FIXEDIMAGE: + pNewWindow = VclPtr<ImageControl>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXImageControl; + break; + case WindowType::FIXEDLINE: + pNewWindow = VclPtr<FixedLine>::Create( pParent, nWinBits ); + break; + case WindowType::FIXEDTEXT: + pNewWindow = VclPtr<FixedText>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXFixedText; + break; + case WindowType::FLOATINGWINDOW: + pNewWindow = VclPtr<FloatingWindow>::Create( pParent, nWinBits ); + break; + case WindowType::GROUPBOX: + pNewWindow = VclPtr<GroupBox>::Create( pParent, nWinBits ); + if ( bFrameControl ) + { + GroupBox* pGroupBox = static_cast< GroupBox* >( pNewWindow.get() ); + *ppNewComp = new VCLXFrame; + // Frame control needs to receive + // Mouse events + pGroupBox->SetMouseTransparent( false ); + } + break; + case WindowType::HELPBUTTON: + pNewWindow = VclPtr<HelpButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::IMAGEBUTTON: + pNewWindow = VclPtr<ImageButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::INFOBOX: + pNewWindow = VclPtr<InfoBox>::Create( pParent, OUString() ); + *ppNewComp = new VCLXMessageBox; + break; + case WindowType::LISTBOX: + pNewWindow = VclPtr<ListBox>::Create( pParent, nWinBits|WB_SIMPLEMODE|WB_AUTOHSCROLL ); + static_cast<ListBox*>(pNewWindow.get())->EnableAutoSize( false ); + *ppNewComp = new VCLXListBox; + break; + case WindowType::LONGCURRENCYBOX: + pNewWindow = VclPtr<LongCurrencyBox>::Create( pParent, nWinBits ); + break; + case WindowType::MENUBUTTON: + pNewWindow = VclPtr<MenuButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::MESSBOX: + pNewWindow = VclPtr<MessBox>::Create( pParent, nMessBoxStyle, nWinBits, OUString(), OUString() ); + *ppNewComp = new VCLXMessageBox; + break; + case WindowType::METRICBOX: + pNewWindow = VclPtr<MetricBox>::Create( pParent, nWinBits ); + break; + case WindowType::METRICFIELD: + pNewWindow = VclPtr<MetricField>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXMetricField; + static_cast<VCLXFormattedSpinField*>(*ppNewComp)->SetFormatter( static_cast<FormatterBase*>(static_cast<MetricField*>(pNewWindow.get())) ); + break; + case WindowType::DIALOG: + case WindowType::MODALDIALOG: + case WindowType::MODELESSDIALOG: + { + // Modal/Modeless only via Show/Execute + if ( (pParent == nullptr ) && ( rDescriptor.ParentIndex == -1 ) ) + pNewWindow = VclPtr<toolkit::ScrollableDialog>::Create( nullptr, nWinBits, Dialog::InitFlag::NoParent ); + else + pNewWindow = VclPtr<toolkit::ScrollableDialog>::Create( pParent, nWinBits ); + // #i70217# Don't always create a new component object. It's possible that VCL has called + // GetComponentInterface( sal_True ) in the Dialog ctor itself (see Window::IsTopWindow() ) + // which creates a component object. + css::uno::Reference< css::awt::XWindowPeer > xWinPeer = pNewWindow->GetComponentInterface( false ); + if ( xWinPeer.is() ) + *ppNewComp = dynamic_cast< VCLXDialog* >( xWinPeer.get() ); + else + *ppNewComp = new VCLXDialog; + } + break; + case WindowType::MOREBUTTON: + pNewWindow = VclPtr<MoreButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::MULTILISTBOX: + pNewWindow = VclPtr<MultiListBox>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXListBox; + break; + case WindowType::NUMERICBOX: + pNewWindow = VclPtr<NumericBox>::Create( pParent, nWinBits ); + break; + case WindowType::OKBUTTON: + pNewWindow = VclPtr<OKButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::PATTERNBOX: + pNewWindow = VclPtr<PatternBox>::Create( pParent, nWinBits ); + break; + case WindowType::PATTERNFIELD: + pNewWindow = VclPtr<PatternField>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXPatternField; + static_cast<VCLXFormattedSpinField*>(*ppNewComp)->SetFormatter( static_cast<FormatterBase*>(static_cast<PatternField*>(pNewWindow.get())) ); + break; + case WindowType::PUSHBUTTON: + pNewWindow = VclPtr<PushButton>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXButton; + break; + case WindowType::QUERYBOX: + pNewWindow = VclPtr<QueryBox>::Create( pParent, nMessBoxStyle, nWinBits, OUString() ); + *ppNewComp = new VCLXMessageBox; + break; + case WindowType::RADIOBUTTON: + pNewWindow = VclPtr<RadioButton>::Create(pParent, false, nWinBits); + *ppNewComp = new VCLXRadioButton; + + // by default, disable RadioCheck + // Since the VCLXRadioButton really cares for its RadioCheck settings, this is important: + // if we enable it, the VCLXRadioButton will use RadioButton::Check instead of RadioButton::SetState + // This leads to a strange behaviour if the control is newly created: when settings the initial + // state to "checked", the RadioButton::Check (called because RadioCheck=sal_True) will uncheck + // _all_other_ radio buttons in the same group. However, at this moment the grouping of the controls + // is not really valid: the controls are grouped after they have been created, but we're still in + // the creation process, so the RadioButton::Check relies on invalid grouping information. + // 07.08.2001 - #87254# - frank.schoenheit@sun.com + static_cast<RadioButton*>(pNewWindow.get())->EnableRadioCheck( false ); + break; + case WindowType::SCROLLBAR: + pNewWindow = VclPtr<ScrollBar>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXScrollBar; + break; + case WindowType::SCROLLBARBOX: + pNewWindow = VclPtr<ScrollBarBox>::Create( pParent, nWinBits ); + break; + case WindowType::SPINBUTTON: + pNewWindow = VclPtr<SpinButton>::Create( pParent, nWinBits ); + *ppNewComp = new ::toolkit::VCLXSpinButton; + break; + case WindowType::SPINFIELD: + pNewWindow = VclPtr<SpinField>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXNumericField; + break; + case WindowType::SPLITTER: + pNewWindow = VclPtr<Splitter>::Create( pParent, nWinBits ); + break; + case WindowType::SPLITWINDOW: + pNewWindow = VclPtr<SplitWindow>::Create( pParent, nWinBits ); + break; + case WindowType::STATUSBAR: + pNewWindow = VclPtr<StatusBar>::Create( pParent, nWinBits ); + break; + case WindowType::TOOLKIT_SYSTEMCHILDWINDOW: + pNewWindow = VclPtr<SystemChildWindow>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXSystemDependentWindow(); + break; + case WindowType::TABCONTROL: + pNewWindow = VclPtr<TabControl>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXMultiPage; + break; + case WindowType::TABDIALOG: + pNewWindow = VclPtr<TabDialog>::Create( pParent, nWinBits ); + break; + case WindowType::TABPAGE: + { + pNewWindow = VclPtr<TabPage>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXTabPage; + } + break; + case WindowType::TIMEBOX: + pNewWindow = VclPtr<TimeBox>::Create( pParent, nWinBits ); + break; + case WindowType::TIMEFIELD: + pNewWindow = VclPtr<TimeField>::Create( pParent, nWinBits ); + static_cast<TimeField*>(pNewWindow.get())->EnableEmptyFieldValue( true ); + *ppNewComp = new VCLXTimeField; + static_cast<VCLXFormattedSpinField*>(*ppNewComp)->SetFormatter( static_cast<FormatterBase*>(static_cast<TimeField*>(pNewWindow.get())) ); + break; + case WindowType::TOOLBOX: + pNewWindow = VclPtr<ToolBox>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXToolBox; + break; + case WindowType::TRISTATEBOX: + pNewWindow = VclPtr<CheckBox>::Create( pParent, nWinBits ); + static_cast<CheckBox*>(pNewWindow.get())->EnableTriState(true); + break; + case WindowType::WARNINGBOX: + pNewWindow = VclPtr<WarningBox>::Create( pParent, nMessBoxStyle, nWinBits, OUString() ); + *ppNewComp = new VCLXMessageBox; + break; + case WindowType::WORKWINDOW: + case WindowType::WINDOW: + case WindowType::TOOLKIT_FRAMEWINDOW: + case WindowType::DOCKINGWINDOW: + if ( rDescriptor.Type == css::awt::WindowClass_TOP ) + { + if (nType == WindowType::DOCKINGWINDOW ) + pNewWindow = VclPtr<DockingWindow>::Create( pParent, nWinBits ); + else + { + if ((pParent == nullptr) && rDescriptor.Parent.is()) + { + // try to get a system dependent window handle + css::uno::Reference< css::awt::XSystemDependentWindowPeer > xSystemDepParent(rDescriptor.Parent, css::uno::UNO_QUERY); + + if (xSystemDepParent.is()) + { + sal_Int8 processID[16]; + + rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(processID) ); + + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + css::uno::Sequence<sal_Int8> processIdSeq(processID, 16); + + css::uno::Any anyHandle = xSystemDepParent->getWindowHandle(processIdSeq, SYSTEM_DEPENDENT_TYPE); + + // use sal_Int64 here to accommodate all int types + // uno::Any shift operator whill upcast if necessary + sal_Int64 nWindowHandle = 0; + bool bXEmbed = false; + + bool bUseParentData = true; + if( ! (anyHandle >>= nWindowHandle) ) + { + css::uno::Sequence< css::beans::NamedValue > aProps; + if( anyHandle >>= aProps ) + { + for( const css::beans::NamedValue& rProp : std::as_const(aProps) ) + { + if ( rProp.Name == "WINDOW" ) + rProp.Value >>= nWindowHandle; + else if ( rProp.Name == "XEMBED" ) + rProp.Value >>= bXEmbed; + } + } + else + bUseParentData = false; + } + + if( bUseParentData ) + { + SystemParentData aParentData; + aParentData.nSize = sizeof( aParentData ); + #if defined MACOSX + aParentData.pView = reinterpret_cast<NSView*>(nWindowHandle); + #elif defined ANDROID + // Nothing + #elif defined IOS + // Nothing + #elif defined UNX + aParentData.aWindow = nWindowHandle; + aParentData.bXEmbedSupport = bXEmbed; + #elif defined _WIN32 + aParentData.hWnd = reinterpret_cast<HWND>(nWindowHandle); + #endif + pNewWindow = VclPtr<WorkWindow>::Create( &aParentData ); + } + } + } + + if (!pNewWindow) + pNewWindow = VclPtr<WorkWindow>::Create( pParent, nWinBits ); + } + + *ppNewComp = new VCLXTopWindow(); + } + else if ( rDescriptor.Type == css::awt::WindowClass_CONTAINER ) + { + if (nType == WindowType::DOCKINGWINDOW ) + pNewWindow = VclPtr<DockingWindow>::Create( pParent, nWinBits ); + else + pNewWindow = VclPtr<vcl::Window>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXContainer; + } + else + { + if (nType == WindowType::DOCKINGWINDOW ) + pNewWindow = VclPtr<DockingWindow>::Create( pParent, nWinBits ); + else + pNewWindow = VclPtr<vcl::Window>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXWindow; + } + break; + case WindowType::CONTROL: + if ( rDescriptor.WindowServiceName.equalsIgnoreAsciiCase( + "tabpagecontainer" ) ) + { + // TabControl has a special case for tabs without border: they are displayed + // in a different way, so we need to ensure that this style is not set, so + // we can guarantee normal tab behavior + pNewWindow = VclPtr<TabControl>::Create( pParent, nWinBits & (~WB_NOBORDER)); + *ppNewComp = new VCLXTabPageContainer; + } + else if ( aServiceName == "animatedimages" ) + { + pNewWindow = VclPtr<Throbber>::Create( pParent, nWinBits ); + *ppNewComp = new ::toolkit::AnimatedImagesPeer; + } + else if (aServiceName == "roadmap") + { + pNewWindow = VclPtr<::vcl::ORoadmap>::Create( pParent, WB_TABSTOP ); + *ppNewComp = new SVTXRoadmap; + } + else if (aServiceName == "fixedhyperlink") + { + pNewWindow = VclPtr<FixedHyperlink>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXFixedHyperlink; + } + else if (aServiceName == "progressbar") + { + pNewWindow = VclPtr<ProgressBar>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXProgressBar; + } + else if (aServiceName == "filecontrol") + { + pNewWindow = VclPtr<FileControl>::Create( pParent, nWinBits ); + *ppNewComp = new VCLXFileControl; + } + else if (aServiceName == "tree") + { + TreeControlPeer* pPeer = new TreeControlPeer; + *ppNewComp = pPeer; + pNewWindow = pPeer->createVclControl( pParent, nWinBits ); + } + else if (aServiceName == "formattedfield") + { + pNewWindow = VclPtr<FormattedField>::Create( pParent, nWinBits ); + *ppNewComp = new SVTXFormattedField; + } + else if (aServiceName == "numericfield") + { + pNewWindow = VclPtr<DoubleNumericField>::Create( pParent, nWinBits ); + *ppNewComp = new SVTXNumericField; + } + else if (aServiceName == "longcurrencyfield") + { + pNewWindow = VclPtr<DoubleCurrencyField>::Create( pParent, nWinBits ); + *ppNewComp = new SVTXCurrencyField; + } + break; + default: + OSL_ENSURE( false, "VCLXToolkit::ImplCreateWindow: unknown window type!" ); + break; + } + } + + // tdf#126717 default that formcontrols show accelerators + if (Control* pControl = dynamic_cast<Control*>(pNewWindow.get())) + pControl->SetShowAccelerator(true); + return pNewWindow; +} + +#ifndef DISABLE_DYNLOADING + +extern "C" { static void thisModule() {} } + +#else + +extern "C" vcl::Window* SAL_CALL CreateWindow( VCLXWindow** ppNewComp, const css::awt::WindowDescriptor* pDescriptor, vcl::Window* pParent, WinBits nWinBits ); + +#endif + +css::uno::Reference< css::awt::XWindowPeer > VCLXToolkit::ImplCreateWindow( + const css::awt::WindowDescriptor& rDescriptor, + MessBoxStyle nForceMessBoxStyle ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + SolarMutexGuard aSolarGuard; + + css::uno::Reference< css::awt::XWindowPeer > xRef; + + VclPtr<vcl::Window> pParent; + if ( rDescriptor.Parent.is() ) + { + VCLXWindow* pParentComponent = comphelper::getUnoTunnelImplementation<VCLXWindow>( rDescriptor.Parent ); + + // #103939# Don't throw assertion, may be it's a system dependent window, used in ImplCreateWindow. + // DBG_ASSERT( pParentComponent, "ParentComponent not valid" ); + + if ( pParentComponent ) + pParent = pParentComponent->GetWindow(); + } + std::pair<WinBits, MessBoxStyle> aPair = ImplGetWinBits( rDescriptor.WindowAttributes, + ImplGetComponentType( rDescriptor.WindowServiceName ) ); + WinBits nWinBits = aPair.first; + aPair.second |= nForceMessBoxStyle; + + VCLXWindow* pNewComp = nullptr; + + vcl::Window* pNewWindow = nullptr; + // Try to create the window with SvTools + // (do this _before_ creating it on our own: The old mechanism (extended toolkit in SvTools) did it this way, + // and we need to stay compatible) + // try to load the lib + if ( !fnSvtCreateWindow +#ifndef DISABLE_DYNLOADING + && !hSvToolsLib +#endif + ) + { +#ifndef DISABLE_DYNLOADING + OUString aLibName(SVT_DLL_NAME); + hSvToolsLib = osl_loadModuleRelative( + &thisModule, aLibName.pData, SAL_LOADMODULE_DEFAULT ); + if ( hSvToolsLib ) + { + OUString aFunctionName( "CreateWindow" ); + fnSvtCreateWindow = reinterpret_cast<FN_SvtCreateWindow>(osl_getFunctionSymbol( hSvToolsLib, aFunctionName.pData )); + } +#else + fnSvtCreateWindow = CreateWindow; +#endif + } + // ask the SvTool creation function + if ( fnSvtCreateWindow ) + pNewWindow = fnSvtCreateWindow( &pNewComp, &rDescriptor, pParent, nWinBits ); + + // if SvTools could not provide a window, create it ourself + if ( !pNewWindow ) + pNewWindow = ImplCreateWindow( &pNewComp, rDescriptor, pParent, nWinBits, aPair.second ); + + DBG_ASSERT( pNewWindow, "createWindow: Unknown Component!" ); + SAL_INFO_IF( !pNewComp, "toolkit", "createWindow: No special Interface!" ); + + if ( pNewWindow ) + { + pNewWindow->SetCreatedWithToolkit( true ); + //pNewWindow->SetPosPixel( Point() ); // do not force (0,0) position, keep default pos instead + + if ( rDescriptor.WindowAttributes & css::awt::WindowAttribute::MINSIZE ) + { + pNewWindow->SetSizePixel( Size() ); + } + else if ( rDescriptor.WindowAttributes & css::awt::WindowAttribute::FULLSIZE ) + { + if ( pParent ) + pNewWindow->SetSizePixel( pParent->GetOutputSizePixel() ); + } + else if ( !VCLUnoHelper::IsZero( rDescriptor.Bounds ) ) + { + tools::Rectangle aRect = VCLRectangle( rDescriptor.Bounds ); + pNewWindow->SetPosSizePixel( aRect.TopLeft(), aRect.GetSize() ); + } + + if ( !pNewComp ) + { + // Default-Interface + xRef = pNewWindow->GetComponentInterface(); + } + else + { + xRef = pNewComp; + pNewWindow->SetComponentInterface( xRef ); + } + DBG_ASSERT( pNewWindow->GetComponentInterface( false ) == xRef, + "VCLXToolkit::createWindow: did #133706# resurge?" ); + + if ( rDescriptor.WindowAttributes & css::awt::WindowAttribute::SHOW ) + pNewWindow->Show(); + } + + return xRef; +} + +css::uno::Sequence< css::uno::Reference< css::awt::XWindowPeer > > VCLXToolkit::createWindows( const css::uno::Sequence< css::awt::WindowDescriptor >& rDescriptors ) +{ + ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); + + sal_uInt32 nComponents = rDescriptors.getLength(); + css::uno::Sequence< css::uno::Reference< css::awt::XWindowPeer > > aSeq( nComponents ); + for ( sal_uInt32 n = 0; n < nComponents; n++ ) + { + css::awt::WindowDescriptor aDescr = rDescriptors.getConstArray()[n]; + + if ( aDescr.ParentIndex == -1 ) + aDescr.Parent = nullptr; + else if ( ( aDescr.ParentIndex >= 0 ) && ( aDescr.ParentIndex < static_cast<short>(n) ) ) + aDescr.Parent = aSeq.getConstArray()[aDescr.ParentIndex]; + aSeq.getArray()[n] = createWindow( aDescr ); + } + return aSeq; +} + +// css::awt::XSystemChildFactory +css::uno::Reference< css::awt::XWindowPeer > VCLXToolkit::createSystemChild( const css::uno::Any& Parent, const css::uno::Sequence< sal_Int8 >& /*ProcessId*/, sal_Int16 nSystemType ) +{ + VclPtr<vcl::Window> pChildWindow; + if ( nSystemType == SYSTEM_DEPENDENT_TYPE ) + { + // use sal_Int64 here to accommodate all int types + // uno::Any shift operator whill upcast if necessary + sal_Int64 nWindowHandle = 0; + bool bXEmbed = false; + + bool bUseParentData = true; + if( ! (Parent >>= nWindowHandle) ) + { + css::uno::Sequence< css::beans::NamedValue > aProps; + if( Parent >>= aProps ) + { + for( const css::beans::NamedValue& rProp : std::as_const(aProps) ) + { + if ( rProp.Name == "WINDOW" ) + rProp.Value >>= nWindowHandle; + else if ( rProp.Name == "XEMBED" ) + rProp.Value >>= bXEmbed; + } + } + else + bUseParentData = false; + } + + if( bUseParentData ) + { + SystemParentData aParentData; + aParentData.nSize = sizeof( aParentData ); + #if defined MACOSX + aParentData.pView = reinterpret_cast<NSView*>(nWindowHandle); + #elif defined ANDROID + // Nothing + #elif defined IOS + // Nothing + #elif defined UNX + aParentData.aWindow = nWindowHandle; + aParentData.bXEmbedSupport = bXEmbed; + #elif defined _WIN32 + aParentData.hWnd = reinterpret_cast<HWND>(nWindowHandle); + #endif + SolarMutexGuard aGuard; + try + { + pChildWindow.reset( VclPtr<WorkWindow>::Create( &aParentData ) ); + } + catch ( const css::uno::RuntimeException & ) + { + // system child window could not be created + DBG_UNHANDLED_EXCEPTION("toolkit"); + pChildWindow.clear(); + } + } + } + else if (nSystemType == css::lang::SystemDependent::SYSTEM_JAVA) + { + SolarMutexGuard aGuard; + pChildWindow.reset(VclPtr<WorkWindow>::Create(nullptr, Parent)); + } + + css::uno::Reference< css::awt::XWindowPeer > xPeer; + if ( pChildWindow ) + { + VCLXTopWindow* pPeer = new VCLXTopWindow; + SolarMutexGuard aGuard; + pPeer->SetWindow( pChildWindow ); + xPeer = pPeer; + } + + return xPeer; +} + +// css::awt::XMessageBoxFactory +css::uno::Reference< css::awt::XMessageBox > SAL_CALL VCLXToolkit::createMessageBox( + const css::uno::Reference< css::awt::XWindowPeer >& aParent, + css::awt::MessageBoxType eType, + ::sal_Int32 aButtons, + const OUString& aTitle, + const OUString& aMessage ) +{ + css::awt::WindowDescriptor aDescriptor; + + sal_Int32 nWindowAttributes = css::awt::WindowAttribute::BORDER|css::awt::WindowAttribute::MOVEABLE|css::awt::WindowAttribute::CLOSEABLE; + + // Map button definitions to window attributes + if (( aButtons & 0x0000ffffL ) == css::awt::MessageBoxButtons::BUTTONS_OK ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::OK; + else if (( aButtons & 0x0000ffffL ) == css::awt::MessageBoxButtons::BUTTONS_OK_CANCEL ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::OK_CANCEL; + else if (( aButtons & 0x0000ffffL ) == css::awt::MessageBoxButtons::BUTTONS_YES_NO ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::YES_NO; + else if (( aButtons & 0x0000ffffL ) == css::awt::MessageBoxButtons::BUTTONS_YES_NO_CANCEL ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::YES_NO_CANCEL; + else if (( aButtons & 0x0000ffffL ) == css::awt::MessageBoxButtons::BUTTONS_RETRY_CANCEL ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::RETRY_CANCEL; + + // Map default button definitions to window attributes + if (sal_Int32( aButtons & 0xffff0000L ) == css::awt::MessageBoxButtons::DEFAULT_BUTTON_OK ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::DEF_OK; + else if (sal_Int32( aButtons & 0xffff0000L ) == css::awt::MessageBoxButtons::DEFAULT_BUTTON_CANCEL ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::DEF_CANCEL; + else if (sal_Int32( aButtons & 0xffff0000L ) == css::awt::MessageBoxButtons::DEFAULT_BUTTON_YES ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::DEF_YES; + else if (sal_Int32( aButtons & 0xffff0000L ) == css::awt::MessageBoxButtons::DEFAULT_BUTTON_NO ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::DEF_NO; + else if (sal_Int32( aButtons & 0xffff0000L ) == css::awt::MessageBoxButtons::DEFAULT_BUTTON_RETRY ) + nWindowAttributes |= css::awt::VclWindowPeerAttribute::DEF_RETRY; + + // No more bits for VclWindowPeerAttribute possible. Mapping must be + // done explicitly using VCL methods + MessBoxStyle nAddWinBits = MessBoxStyle::NONE; + if (( aButtons & 0x0000ffffL ) == css::awt::MessageBoxButtons::BUTTONS_ABORT_IGNORE_RETRY ) + nAddWinBits |= MessBoxStyle::AbortRetryIgnore; + if ( sal_Int32( aButtons & 0xffff0000L ) == css::awt::MessageBoxButtons::DEFAULT_BUTTON_IGNORE ) + nAddWinBits |= MessBoxStyle::DefaultIgnore; + + OUString aType; + lcl_convertMessageBoxType( aType, eType ); + + aDescriptor.Type = css::awt::WindowClass_MODALTOP; + aDescriptor.WindowServiceName = aType; + aDescriptor.ParentIndex = -1; + aDescriptor.Parent = aParent; + aDescriptor.WindowAttributes = nWindowAttributes; + css::uno::Reference< css::awt::XMessageBox > xMsgBox( + ImplCreateWindow( aDescriptor, nAddWinBits ), css::uno::UNO_QUERY ); + css::uno::Reference< css::awt::XWindow > xWindow( xMsgBox, css::uno::UNO_QUERY ); + if ( xMsgBox.is() && xWindow.is() ) + { + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if ( pWindow ) + { + SolarMutexGuard aGuard; + xMsgBox->setCaptionText( aTitle ); + xMsgBox->setMessageText( aMessage ); + } + } + + return xMsgBox; +} + +css::uno::Reference< css::datatransfer::dnd::XDragGestureRecognizer > SAL_CALL VCLXToolkit::getDragGestureRecognizer( const css::uno::Reference< css::awt::XWindow >& window ) +{ + SolarMutexGuard g; + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( window ); + + if( pWindow ) + return pWindow->GetDragGestureRecognizer(); + + return css::uno::Reference< css::datatransfer::dnd::XDragGestureRecognizer >(); +} + +css::uno::Reference< css::datatransfer::dnd::XDragSource > SAL_CALL VCLXToolkit::getDragSource( const css::uno::Reference< css::awt::XWindow >& window ) +{ + SolarMutexGuard g; + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( window ); + + if( pWindow ) + return pWindow->GetDragSource(); + + return css::uno::Reference< css::datatransfer::dnd::XDragSource >(); +} + +css::uno::Reference< css::datatransfer::dnd::XDropTarget > SAL_CALL VCLXToolkit::getDropTarget( const css::uno::Reference< css::awt::XWindow >& window ) +{ + SolarMutexGuard g; + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( window ); + + if( pWindow ) + return pWindow->GetDropTarget(); + + return css::uno::Reference< css::datatransfer::dnd::XDropTarget >(); +} + +css::uno::Reference< css::datatransfer::clipboard::XClipboard > SAL_CALL VCLXToolkit::getClipboard( const OUString& clipboardName ) +{ + if( clipboardName.isEmpty() ) + { + if( !mxClipboard.is() ) + { + // remember clipboard here + mxClipboard = css::datatransfer::clipboard::SystemClipboard::create( + comphelper::getProcessComponentContext()); + } + + return mxClipboard; + } + + else if( clipboardName == "Selection" ) + { + return mxSelection; + } + + return css::uno::Reference< css::datatransfer::clipboard::XClipboard >(); +} + +// XServiceInfo +OUString VCLXToolkit::getImplementationName() +{ + return "stardiv.Toolkit.VCLXToolkit"; +} + +sal_Bool VCLXToolkit::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > VCLXToolkit::getSupportedServiceNames() +{ + return css::uno::Sequence<OUString>{ + "com.sun.star.awt.Toolkit", "stardiv.vcl.VclToolkit"}; +} + +// css::awt::XExtendedToolkit: + +// virtual +::sal_Int32 SAL_CALL VCLXToolkit::getTopWindowCount() +{ + return static_cast< ::sal_Int32 >(::Application::GetTopWindowCount()); + // XXX numeric overflow +} + +// virtual +css::uno::Reference< css::awt::XTopWindow > SAL_CALL +VCLXToolkit::getTopWindow(::sal_Int32 nIndex) +{ + vcl::Window * p = ::Application::GetTopWindow(static_cast< long >(nIndex)); + // XXX numeric overflow + return css::uno::Reference< css::awt::XTopWindow >( + p == nullptr ? nullptr : static_cast< css::awt::XWindow * >(p->GetWindowPeer()), + css::uno::UNO_QUERY); +} + +// virtual +css::uno::Reference< css::awt::XTopWindow > SAL_CALL +VCLXToolkit::getActiveTopWindow() +{ + vcl::Window * p = ::Application::GetActiveTopWindow(); + return css::uno::Reference< css::awt::XTopWindow >( + p == nullptr ? nullptr : static_cast< css::awt::XWindow * >(p->GetWindowPeer()), + css::uno::UNO_QUERY); +} + +// virtual +void SAL_CALL VCLXToolkit::addTopWindowListener( + css::uno::Reference< css::awt::XTopWindowListener > const & rListener) +{ + OSL_ENSURE(rListener.is(), "Null rListener"); + ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + rListener->disposing( + css::lang::EventObject( + static_cast< ::cppu::OWeakObject * >(this))); + } + else if (m_aTopWindowListeners.addInterface(rListener) == 1 + && !m_bEventListener) + { + m_bEventListener = true; + ::Application::AddEventListener(m_aEventListenerLink); + } +} + +// virtual +void SAL_CALL VCLXToolkit::removeTopWindowListener( + css::uno::Reference< css::awt::XTopWindowListener > const & rListener) +{ + ::osl::MutexGuard aGuard(rBHelper.rMutex); + if (!(rBHelper.bDisposed || rBHelper.bInDispose) + && m_aTopWindowListeners.removeInterface(rListener) == 0 + && m_aFocusListeners.getLength() == 0 && m_bEventListener) + { + ::Application::RemoveEventListener(m_aEventListenerLink); + m_bEventListener = false; + } +} + +// virtual +void SAL_CALL VCLXToolkit::addKeyHandler( + css::uno::Reference< css::awt::XKeyHandler > const & rHandler) +{ + OSL_ENSURE(rHandler.is(), "Null rHandler"); + ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + rHandler->disposing( + css::lang::EventObject( + static_cast< ::cppu::OWeakObject * >(this))); + } + else if (m_aKeyHandlers.addInterface(rHandler) == 1 && !m_bKeyListener) + { + m_bKeyListener = true; + ::Application::AddKeyListener(m_aKeyListenerLink); + } +} + +// virtual +void SAL_CALL VCLXToolkit::removeKeyHandler( + css::uno::Reference< css::awt::XKeyHandler > const & rHandler) +{ + ::osl::MutexGuard aGuard(rBHelper.rMutex); + if (!(rBHelper.bDisposed || rBHelper.bInDispose) + && m_aKeyHandlers.removeInterface(rHandler) == 0 && m_bKeyListener) + { + ::Application::RemoveKeyListener(m_aKeyListenerLink); + m_bKeyListener = false; + } +} + +// virtual +void SAL_CALL VCLXToolkit::addFocusListener( + css::uno::Reference< css::awt::XFocusListener > const & rListener) +{ + OSL_ENSURE(rListener.is(), "Null rListener"); + ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + rListener->disposing( + css::lang::EventObject( + static_cast< ::cppu::OWeakObject * >(this))); + } + else if (m_aFocusListeners.addInterface(rListener) == 1 + && !m_bEventListener) + { + m_bEventListener = true; + ::Application::AddEventListener(m_aEventListenerLink); + } +} + +// virtual +void SAL_CALL VCLXToolkit::removeFocusListener( + css::uno::Reference< css::awt::XFocusListener > const & rListener) +{ + ::osl::MutexGuard aGuard(rBHelper.rMutex); + if (!(rBHelper.bDisposed || rBHelper.bInDispose) + && m_aFocusListeners.removeInterface(rListener) == 0 + && m_aTopWindowListeners.getLength() == 0 && m_bEventListener) + { + ::Application::RemoveEventListener(m_aEventListenerLink); + m_bEventListener = false; + } +} + +// virtual +void SAL_CALL VCLXToolkit::fireFocusGained( + css::uno::Reference< + css::uno::XInterface > const &) +{ +} + +// virtual +void SAL_CALL VCLXToolkit::fireFocusLost( + css::uno::Reference< + css::uno::XInterface > const &) +{ +} + + +IMPL_LINK(VCLXToolkit, eventListenerHandler, ::VclSimpleEvent&, rEvent, void) +{ + switch (rEvent.GetId()) + { + case VclEventId::WindowShow: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowOpened); + break; + case VclEventId::WindowHide: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowClosed); + break; + case VclEventId::WindowActivate: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowActivated); + break; + case VclEventId::WindowDeactivate: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowDeactivated); + break; + case VclEventId::WindowClose: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowClosing); + break; + case VclEventId::WindowGetFocus: + callFocusListeners(&rEvent, true); + break; + case VclEventId::WindowLoseFocus: + callFocusListeners(&rEvent, false); + break; + case VclEventId::WindowMinimize: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowMinimized); + break; + case VclEventId::WindowNormalize: + callTopWindowListeners( + &rEvent, &css::awt::XTopWindowListener::windowNormalized); + break; + default: break; + } +} + +IMPL_LINK(VCLXToolkit, keyListenerHandler, ::VclWindowEvent&, rEvent, bool) +{ + switch (rEvent.GetId()) + { + case VclEventId::WindowKeyInput: + return callKeyHandlers(&rEvent, true); + case VclEventId::WindowKeyUp: + return callKeyHandlers(&rEvent, false); + default: break; + } + return false; +} + +void VCLXToolkit::callTopWindowListeners( + ::VclSimpleEvent const * pEvent, + void (SAL_CALL css::awt::XTopWindowListener::* pFn)( + css::lang::EventObject const &)) +{ + vcl::Window * pWindow + = static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow(); + if (pWindow->IsTopWindow()) + { + std::vector< css::uno::Reference< css::uno::XInterface > > + aListeners(m_aTopWindowListeners.getElements()); + if (!aListeners.empty()) + { + css::lang::EventObject aAwtEvent( + static_cast< css::awt::XWindow * >(pWindow->GetWindowPeer())); + for (const css::uno::Reference<XInterface> & i : aListeners) + { + css::uno::Reference< css::awt::XTopWindowListener > + xListener(i, css::uno::UNO_QUERY); + try + { + (xListener.get()->*pFn)(aAwtEvent); + } + catch (const css::uno::RuntimeException &) + { + DBG_UNHANDLED_EXCEPTION("toolkit"); + } + } + } + } +} + +bool VCLXToolkit::callKeyHandlers(::VclSimpleEvent const * pEvent, + bool bPressed) +{ + std::vector< css::uno::Reference< css::uno::XInterface > > + aHandlers(m_aKeyHandlers.getElements()); + + if (!aHandlers.empty()) + { + vcl::Window * pWindow = static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow(); + + // See implementation in vclxwindow.cxx for mapping between VCL and UNO AWT event + ::KeyEvent * pKeyEvent = static_cast< ::KeyEvent * >( + static_cast< ::VclWindowEvent const * >(pEvent)->GetData()); + css::awt::KeyEvent aAwtEvent( + static_cast< css::awt::XWindow * >(pWindow->GetWindowPeer()), + (pKeyEvent->GetKeyCode().IsShift() + ? css::awt::KeyModifier::SHIFT : 0) + | (pKeyEvent->GetKeyCode().IsMod1() + ? css::awt::KeyModifier::MOD1 : 0) + | (pKeyEvent->GetKeyCode().IsMod2() + ? css::awt::KeyModifier::MOD2 : 0) + | (pKeyEvent->GetKeyCode().IsMod3() + ? css::awt::KeyModifier::MOD3 : 0), + pKeyEvent->GetKeyCode().GetCode(), pKeyEvent->GetCharCode(), + sal::static_int_cast< sal_Int16 >( + pKeyEvent->GetKeyCode().GetFunction())); + for (const css::uno::Reference<XInterface> & i : aHandlers) + { + css::uno::Reference< css::awt::XKeyHandler > xHandler( + i, css::uno::UNO_QUERY); + try + { + if (bPressed ? xHandler->keyPressed(aAwtEvent) + : xHandler->keyReleased(aAwtEvent)) + return true; + } + catch (const css::uno::RuntimeException &) + { + DBG_UNHANDLED_EXCEPTION("toolkit"); + } + } + } + return false; +} + +void VCLXToolkit::callFocusListeners(::VclSimpleEvent const * pEvent, + bool bGained) +{ + vcl::Window * pWindow + = static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow(); + if (pWindow->IsTopWindow()) + { + std::vector< css::uno::Reference< css::uno::XInterface > > + aListeners(m_aFocusListeners.getElements()); + if (!aListeners.empty()) + { + // Ignore the interior of compound controls when determining the + // window that gets the focus next (see implementation in + // vclxwindow.cxx for mapping between VCL and UNO AWT event): + css::uno::Reference< css::uno::XInterface > xNext; + vcl::Window * pFocus = ::Application::GetFocusWindow(); + for (vcl::Window * p = pFocus; p != nullptr; p = p->GetParent()) + if (!p->IsCompoundControl()) + { + pFocus = p; + break; + } + if (pFocus != nullptr) + xNext = pFocus->GetComponentInterface(); + css::awt::FocusEvent aAwtEvent( + static_cast< css::awt::XWindow * >(pWindow->GetWindowPeer()), + static_cast<sal_Int16>(pWindow->GetGetFocusFlags()), + xNext, false); + for (const css::uno::Reference<XInterface> & i : aListeners) + { + css::uno::Reference< css::awt::XFocusListener > xListener( + i, css::uno::UNO_QUERY); + try + { + bGained ? xListener->focusGained(aAwtEvent) + : xListener->focusLost(aAwtEvent); + } + catch (const css::uno::RuntimeException &) + { + DBG_UNHANDLED_EXCEPTION("toolkit"); + } + } + } + } +} + +// css::awt::XReschedule: + +void SAL_CALL VCLXToolkit::reschedule() +{ + SolarMutexGuard aSolarGuard; + Application::Reschedule(true); +} + +// css::awt::XToolkitExperimental + +void SAL_CALL VCLXToolkit::processEventsToIdle() +{ + SolarMutexGuard aSolarGuard; + comphelper::ProfileZone aZone("processEvents"); + Scheduler::ProcessEventsToIdle(); +} + +sal_Int64 SAL_CALL VCLXToolkit::getOpenGLBufferSwapCounter() +{ +#if HAVE_FEATURE_OPENGL + return OpenGLWrapper::getBufferSwapCounter(); +#else + return 0; +#endif +} + +void SAL_CALL VCLXToolkit::setDeterministicScheduling(sal_Bool bDeterministicMode) +{ + SolarMutexGuard aSolarGuard; + Scheduler::SetDeterministicMode(bDeterministicMode); +} + +void SAL_CALL VCLXToolkit::pause(sal_Int32 nMilliseconds) +{ + new Pause(nMilliseconds); +} + +void SAL_CALL VCLXToolkit::startRecording() +{ + ::comphelper::ProfileRecording::startRecording(true); +} + +void SAL_CALL VCLXToolkit::stopRecording() +{ + ::comphelper::ProfileRecording::startRecording( false ); +} + +css::uno::Sequence< OUString > VCLXToolkit::getRecordingAndClear() +{ + return ::comphelper::ProfileRecording::getRecordingAndClear(); +} + +// css:awt:XToolkitRobot + +void SAL_CALL VCLXToolkit::keyPress( const css::awt::KeyEvent & aKeyEvent ) +{ + css::uno::Reference<css::awt::XWindow> xWindow ( aKeyEvent.Source, css::uno::UNO_QUERY_THROW ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( !pWindow ) + throw css::uno::RuntimeException( "invalid event source" ); + + ::KeyEvent aVCLKeyEvent = VCLUnoHelper::createVCLKeyEvent( aKeyEvent ); + ::Application::PostKeyEvent( VclEventId::WindowKeyInput, pWindow, &aVCLKeyEvent ); +} + +void SAL_CALL VCLXToolkit::keyRelease( const css::awt::KeyEvent & aKeyEvent ) +{ + css::uno::Reference<css::awt::XWindow> xWindow ( aKeyEvent.Source, css::uno::UNO_QUERY_THROW ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( !pWindow ) + throw css::uno::RuntimeException( "invalid event source" ); + + ::KeyEvent aVCLKeyEvent = VCLUnoHelper::createVCLKeyEvent( aKeyEvent ); + ::Application::PostKeyEvent( VclEventId::WindowKeyUp, pWindow, &aVCLKeyEvent ); +} + + +void SAL_CALL VCLXToolkit::mousePress( const css::awt::MouseEvent & aMouseEvent ) +{ + css::uno::Reference<css::awt::XWindow> xWindow ( aMouseEvent.Source, css::uno::UNO_QUERY_THROW ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( !pWindow ) + throw css::uno::RuntimeException( "invalid event source" ); + + ::MouseEvent aVCLMouseEvent = VCLUnoHelper::createVCLMouseEvent( aMouseEvent ); + ::Application::PostMouseEvent( VclEventId::WindowMouseButtonDown, pWindow, &aVCLMouseEvent ); +} + +void SAL_CALL VCLXToolkit::mouseRelease( const css::awt::MouseEvent & aMouseEvent ) +{ + css::uno::Reference<css::awt::XWindow> xWindow ( aMouseEvent.Source, css::uno::UNO_QUERY_THROW ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( !pWindow ) + throw css::uno::RuntimeException( "invalid event source" ); + + ::MouseEvent aVCLMouseEvent = VCLUnoHelper::createVCLMouseEvent( aMouseEvent ); + ::Application::PostMouseEvent( VclEventId::WindowMouseButtonUp, pWindow, &aVCLMouseEvent ); +} + +void SAL_CALL VCLXToolkit::mouseMove( const css::awt::MouseEvent & aMouseEvent ) +{ + css::uno::Reference<css::awt::XWindow> xWindow ( aMouseEvent.Source, css::uno::UNO_QUERY_THROW ); + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( !pWindow ) + throw css::uno::RuntimeException( "invalid event source" ); + + ::MouseEvent aVCLMouseEvent = VCLUnoHelper::createVCLMouseEvent( aMouseEvent ); + ::Application::PostMouseEvent( VclEventId::WindowMouseMove, pWindow, &aVCLMouseEvent ); +} + + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +stardiv_Toolkit_VCLXToolkit_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new VCLXToolkit()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |