/* -*- 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 "backingwindow.hxx"
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/KeyEvent.hpp>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/awt/XWindow.hpp>
#include <com/sun/star/awt/XKeyListener.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/frame/XFrame.hpp>
#include <com/sun/star/frame/XDispatch.hpp>
#include <com/sun/star/lang/XEventListener.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <cppuhelper/supportsservice.hxx>
#include <cppuhelper/queryinterface.hxx>
#include <cppuhelper/typeprovider.hxx>
#include <cppuhelper/weak.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/svapp.hxx>
#include <vcl/syswin.hxx>
#include <sfx2/notebookbar/SfxNotebookBar.hxx>
#ifdef MACOSX
#include <shutdownicon.hxx>
#endif
namespace {
/**
implements the backing component .
This component is a special one , which doesn ' t provide a controller
nor a model . It supports the following features :
- Drag & Drop
- Key Accelerators
- Simple Menu
- Progress Bar
- Background
*/
class BackingComp : public css::lang::XTypeProvider
, public css::lang::XServiceInfo
, public css::lang::XInitialization
, public css::frame::XController // => XComponent
, public css::awt::XKeyListener // => XEventListener
, public css::frame::XDispatchProvider
, public css::frame::XDispatch
, public ::cppu::OWeakObject
{
private :
/** reference to the component window. */
css::uno::Reference< css::awt::XWindow > m_xWindow;
/** the owner frame of this component. */
css::uno::Reference< css::frame::XFrame > m_xFrame;
Size m_aInitialWindowMinSize;
public :
explicit BackingComp();
// XInterface
virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
virtual void SAL_CALL acquire ( ) noexcept override;
virtual void SAL_CALL release ( ) noexcept override;
// XTypeProvide
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes () override;
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
// XServiceInfo
virtual OUString SAL_CALL getImplementationName ( ) override;
virtual sal_Bool SAL_CALL supportsService ( const OUString& sServiceName ) override;
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
// XInitialization
virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& lArgs ) override;
// XController
virtual void SAL_CALL attachFrame( const css::uno::Reference< css::frame::XFrame >& xFrame ) override;
virtual sal_Bool SAL_CALL attachModel( const css::uno::Reference< css::frame::XModel >& xModel ) override;
virtual sal_Bool SAL_CALL suspend( sal_Bool bSuspend ) override;
virtual css::uno::Any SAL_CALL getViewData() override;
virtual void SAL_CALL restoreViewData( const css::uno::Any& aData ) override;
virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel() override;
virtual css::uno::Reference< css::frame::XFrame > SAL_CALL getFrame() override;
// XKeyListener
virtual void SAL_CALL keyPressed ( const css::awt::KeyEvent& aEvent ) override;
virtual void SAL_CALL keyReleased( const css::awt::KeyEvent& aEvent ) override;
// XEventListener
virtual void SAL_CALL disposing( const css::lang::EventObject& aEvent ) override;
// XComponent
virtual void SAL_CALL dispose ( ) override;
virtual void SAL_CALL addEventListener ( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
// XDispatchProvider
virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& aURL, const OUString& sTargetFrameName , sal_Int32 nSearchFlags ) override;
virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptions ) override;
// XDispatch
virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener, const css::util::URL& aURL ) override;
virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener, const css::util::URL& aURL ) override;
};
BackingComp::BackingComp()
{
}
/** return information about supported interfaces.
Some interfaces are supported by his class directly , but some other ones are
used by aggregation . An instance of this class must provide some window interfaces .
But it must represent a VCL window behind such interfaces too ! So we use an internal
saved window member to ask it for its interfaces and return it . But we must be aware then ,
that it can be destroyed from outside too . . .
@ param aType
describe the required interface type
@ return An Any holding the instance , which provides the queried interface .
Note : There exist two possible results . . . this instance itself and her window member !
*/
css::uno::Any SAL_CALL BackingComp::queryInterface( /*IN*/ const css::uno::Type& aType )
{
// first look for own supported interfaces
css::uno::Any aResult = ::cppu::queryInterface(
aType,
static_cast < css::lang::XTypeProvider* >(this ),
static_cast < css::lang::XServiceInfo* >(this ),
static_cast < css::lang::XInitialization* >(this ),
static_cast < css::frame::XController* >(this ),
static_cast < css::lang::XComponent* >(this ),
static_cast < css::lang::XEventListener* >(this ),
static_cast < css::awt::XKeyListener* >(static_cast < css::lang::XEventListener* >(this )),
static_cast < css::frame::XDispatchProvider* >(this ),
static_cast < css::frame::XDispatch* >(this ) );
// then look for supported window interfaces
// Note: They exist only, if this instance was initialized
// with a valid window reference. It's aggregation on demand ...
if (!aResult.hasValue())
{
/* SAFE { */
SolarMutexGuard aGuard;
if (m_xWindow.is())
aResult = m_xWindow->queryInterface(aType);
/* } SAFE */
}
// look for XWeak and XInterface
if (!aResult.hasValue())
aResult = OWeakObject::queryInterface(aType);
return aResult;
}
/** increase ref count of this instance.
*/
void SAL_CALL BackingComp::acquire()
noexcept
{
OWeakObject::acquire();
}
/** decrease ref count of this instance.
*/
void SAL_CALL BackingComp::release()
noexcept
{
OWeakObject::release();
}
/** return collection about all supported interfaces.
Optimize this method !
We initialize a static variable only one time .
And we don ' t must use a mutex at every call !
For the first call ; pTypeCollection is NULL -
for the second call pTypeCollection is different from NULL !
@ return A list of all supported interface types .
*/
css::uno::Sequence< css::uno::Type > SAL_CALL BackingComp::getTypes()
{
static cppu::OTypeCollection aTypeCollection = [this ]() {
SolarMutexGuard aGuard;
css::uno::Reference<css::lang::XTypeProvider> xProvider(m_xWindow, css::uno::UNO_QUERY);
css::uno::Sequence<css::uno::Type> lWindowTypes;
if (xProvider.is())
lWindowTypes = xProvider->getTypes();
return cppu::OTypeCollection(
cppu::UnoType<css::lang::XInitialization>::get(),
cppu::UnoType<css::lang::XTypeProvider>::get(),
cppu::UnoType<css::lang::XServiceInfo>::get(),
cppu::UnoType<css::frame::XController>::get(),
cppu::UnoType<css::lang::XComponent>::get(),
cppu::UnoType<css::frame::XDispatchProvider>::get(),
cppu::UnoType<css::frame::XDispatch>::get(), lWindowTypes);
}();
return aTypeCollection.getTypes();
}
/** create one unique Id for all instances of this class.
Optimize this method
We initialize a static variable only one time . And we don ' t must use a mutex at every call !
For the first call ; pID is NULL - for the second call pID is different from NULL !
@ return A byte array , which represent the unique id .
*/
css::uno::Sequence< sal_Int8 > SAL_CALL BackingComp::getImplementationId()
{
return css::uno::Sequence<sal_Int8>();
}
OUString SAL_CALL BackingComp::getImplementationName()
{
return u"com.sun.star.comp.sfx2.BackingComp" _ustr;
}
sal_Bool SAL_CALL BackingComp::supportsService( /*IN*/ const OUString& sServiceName )
{
return cppu::supportsService(this , sServiceName);
}
css::uno::Sequence< OUString > SAL_CALL BackingComp::getSupportedServiceNames()
{
return { u"com.sun.star.frame.StartModule" _ustr, u"com.sun.star.frame.ProtocolHandler" _ustr };
}
/**
attach this component to a target frame .
We have to use the container window of this frame as parent window of our own component window .
But it ' s not allowed to work with it really . May another component used it too .
Currently we need it only to create our child component window and support it ' s
interfaces inside our queryInterface ( ) method . The user of us must have e . g . the
XWindow interface of it to be able to call setComponent ( xWindow , xController ) at the
frame !
May he will do the following things :
< listing >
XController xBackingComp = ( XController ) UnoRuntime . queryInterface (
XController . class ,
xSMGR . createInstance ( SERVICENAME_STARTMODULE ) ) ;
// at this time XWindow isn't present at this instance!
XWindow xBackingComp = ( XWindow ) UnoRuntime . queryInterface (
XWindow . class ,
xBackingComp ) ;
// attach controller to the frame
// We will use its container window, to create
// the component window. From now we offer the window interfaces!
xBackingComp . attachFrame ( xFrame ) ;
XWindow xBackingComp = ( XWindow ) UnoRuntime . queryInterface (
XWindow . class ,
xBackingComp ) ;
// Our user can set us at the frame as new component
xFrame . setComponent ( xBackingWin , xBackingComp ) ;
// But that had no effect to our view state.
// We must be started to create our UI elements like e.g. menu, title, background ...
XInitialization xBackingInit = ( XInitialization ) UnoRuntime . queryInterface (
XInitialization . class ,
xBackingComp ) ;
xBackingInit . initialize ( lArgs ) ;
< / listing >
@ param xFrame
reference to our new target frame
@ throw css : : uno : : RuntimeException
if the given frame reference is wrong or component window couldn ' t be created
successfully .
We throw it too , if we already attached to a frame . Because we don ' t support
reparenting of our component window on demand !
*/
void SAL_CALL BackingComp::attachFrame( /*IN*/ const css::uno::Reference< css::frame::XFrame >& xFrame )
{
/* SAFE */
SolarMutexGuard aGuard;
// check some required states
if (m_xFrame.is())
throw css::uno::RuntimeException(
u"already attached" _ustr,
getXWeak());
if (!xFrame.is())
throw css::uno::RuntimeException(
u"invalid frame reference" _ustr,
getXWeak());
if (!m_xWindow.is())
return ; // disposed
// safe the frame reference
m_xFrame = xFrame;
// initialize the component and its parent window
css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow();
VclPtr< WorkWindow > pParent = static_cast <WorkWindow*>(VCLUnoHelper::GetWindow(xParentWindow));
VclPtr< vcl::Window > pWindow = VCLUnoHelper::GetWindow(m_xWindow);
// disable full screen mode of the frame!
if (pParent && pParent->IsFullScreenMode())
{
pParent->ShowFullScreenMode(false );
pParent->SetMenuBarMode(MenuBarMode::Normal);
}
// create the menu bar for the backing component
css::uno::Reference< css::beans::XPropertySet > xPropSet(m_xFrame, css::uno::UNO_QUERY_THROW);
css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
xPropSet->getPropertyValue(u"LayoutManager" _ustr) >>= xLayoutManager;
if (xLayoutManager.is())
{
xLayoutManager->lock();
xLayoutManager->createElement(u"private:resource/menubar/menubar" _ustr);
xLayoutManager->unlock();
}
if (pWindow)
{
// set help ID for our canvas
pWindow->SetHelpId(u"FWK_HID_BACKINGWINDOW" _ustr);
}
// inform BackingWindow about frame
BackingWindow* pBack = dynamic_cast <BackingWindow*>(pWindow.get());
if ( pBack )
pBack->setOwningFrame( m_xFrame );
// Set a minimum size for Start Center
if ( !pParent || !pBack )
return ;
tools::Long nMenuHeight = 0 ;
vcl::Window* pMenu = pParent->GetWindow(GetWindowType::Next);
if ( pMenu )
nMenuHeight = pMenu->GetSizePixel().Height();
m_aInitialWindowMinSize = pParent->GetMinOutputSizePixel();
if (!m_aInitialWindowMinSize.Width())
m_aInitialWindowMinSize.AdjustWidth(1 );
if (!m_aInitialWindowMinSize.Height())
m_aInitialWindowMinSize.AdjustHeight(1 );
pParent->SetMinOutputSizePixel(
Size(
pBack->get_width_request(),
pBack->get_height_request() + nMenuHeight));
#ifdef MACOSX
SystemWindow *pSysWin = pParent.get();
if (pSysWin)
ShutdownIcon::SetDefaultMenuBar(pSysWin->GetMenuBar());
#endif
/* } SAFE */
}
/** not supported.
This component does not know any model . It will be represented by a window and
its controller only .
return < FALSE / > every time .
*/
sal_Bool SAL_CALL BackingComp::attachModel( /*IN*/ const css::uno::Reference< css::frame::XModel >& )
{
return false ;
}
/** not supported.
This component does not know any model . It will be represented by a window and
its controller only .
return An empty reference every time .
*/
css::uno::Reference< css::frame::XModel > SAL_CALL BackingComp::getModel()
{
return css::uno::Reference< css::frame::XModel >();
}
/** not supported.
return An empty value .
*/
css::uno::Any SAL_CALL BackingComp::getViewData()
{
return css::uno::Any();
}
/** not supported.
@ param aData
not used .
*/
void SAL_CALL BackingComp::restoreViewData( /*IN*/ const css::uno::Any& )
{
}
/** returns the attached frame for this component.
@ see attachFrame ( )
@ return The internally saved frame reference .
Can be null , if attachFrame ( ) was not called before .
*/
css::uno::Reference< css::frame::XFrame > SAL_CALL BackingComp::getFrame()
{
/* SAFE { */
SolarMutexGuard aGuard;
return m_xFrame;
/* } SAFE */
}
/** ask controller for its current working state.
If someone wishes to close this component , it must suspend the controller before .
That will be a chance for it to disagree with that AND show any UI for a possible
UI user .
@ param bSuspend
If it ' s set to sal_True this controller should be suspended .
sal_False will resuspend it .
@ return sal_True if the request could be finished successfully ; sal_False otherwise .
*/
sal_Bool SAL_CALL BackingComp::suspend( /*IN*/ sal_Bool )
{
/* FIXME ... implemented by using default :-( */
return true ;
}
/** callback from our window member.
Our internal saved window wish to die . It will be disposed from outside ( may be the frame )
and inform us . We must release its reference only here . Of course we check the given reference
here and reject callback from unknown sources .
Note : deregistration as listener isn ' t necessary here . The broadcaster do it automatically .
@ param aEvent
describe the broadcaster of this callback
@ throw css : : uno : : RuntimeException
if the broadcaster doesn ' t represent the expected window reference .
*/
void SAL_CALL BackingComp::disposing( /*IN*/ const css::lang::EventObject& aEvent )
{
// Attention: don't free m_pAccExec here! see comments inside dtor and
// keyPressed() for further details.
/* SAFE { */
SolarMutexGuard aGuard;
if (!aEvent.Source.is() || aEvent.Source!=m_xWindow || !m_xWindow.is())
throw css::uno::RuntimeException(
u"unexpected source or called twice" _ustr,
getXWeak());
m_xWindow.clear();
/* } SAFE */
}
/** kill this instance.
It can be called from our owner frame only . But there is no possibility to check the caller .
We have to release all our internal used resources and die . From this point we can throw
DisposedExceptions for every further interface request . . . but current implementation doesn ' t do so . . .
*/
void SAL_CALL BackingComp::dispose()
{
/* SAFE { */
SolarMutexGuard aGuard;
if (m_xFrame.is())
{
css::uno::Reference< css::awt::XWindow > xParentWindow = m_xFrame->getContainerWindow();
VclPtr< WorkWindow > pParent = static_cast <WorkWindow*>(VCLUnoHelper::GetWindow(xParentWindow));
if (pParent)
{
pParent->SetMinOutputSizePixel(m_aInitialWindowMinSize);
// hide NotebookBar
sfx2::SfxNotebookBar::CloseMethod(static_cast <SystemWindow*>(pParent));
}
}
// stop listening at the window
if (m_xWindow.is())
{
m_xWindow->removeEventListener(this );
m_xWindow->removeKeyListener(this );
m_xWindow.clear();
}
// forget all other used references
m_xFrame.clear();
/* } SAFE */
}
/** not supported.
@ param xListener
not used .
@ throw css : : uno : : RuntimeException
because the listener expect to be holded alive by this container .
We must inform it about this unsupported feature .
*/
void SAL_CALL BackingComp::addEventListener( /*IN*/ const css::uno::Reference< css::lang::XEventListener >& )
{
throw css::uno::RuntimeException(
u"not supported" _ustr,
getXWeak());
}
/** not supported.
Because registration is not supported too , we must do nothing here . Nobody can call this method really .
@ param xListener
not used .
*/
void SAL_CALL BackingComp::removeEventListener( /*IN*/ const css::uno::Reference< css::lang::XEventListener >& )
{
}
/**
force initialization for this component .
Inside attachFrame ( ) we created our component window . But it was not allowed there , to
initialize it . E . g . the menu must be set at the container window of the frame , which
is our parent window . But may at that time another component used it .
That ' s why our creator has to inform us , when it ' s time to initialize us really .
Currently only calling of this method must be done . But further implementations
can use special in parameter to configure this initialization . . .
@ param lArgs
currently not used
@ throw css : : uno : : RuntimeException
if some resources are missing
Means if may be attachedFrame ( ) wasn ' t called before .
*/
void SAL_CALL BackingComp::initialize( /*IN*/ const css::uno::Sequence< css::uno::Any >& lArgs )
{
/* SAFE { */
SolarMutexGuard aGuard;
if (m_xWindow.is())
throw css::uno::Exception(
u"already initialized" _ustr,
getXWeak());
css::uno::Reference< css::awt::XWindow > xParentWindow;
if (
(lArgs.getLength()!=1 ) ||
(!(lArgs[0 ] >>= xParentWindow)) ||
(!xParentWindow.is() )
)
{
throw css::uno::Exception(
u"wrong or corrupt argument list" _ustr,
getXWeak());
}
// create the component window
VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow(xParentWindow);
VclPtr<vcl::Window> pWindow = VclPtr<BackingWindow>::Create(pParent);
m_xWindow = VCLUnoHelper::GetInterface(pWindow);
if (!m_xWindow.is())
throw css::uno::RuntimeException(
u"couldn't create component window" _ustr,
getXWeak());
// start listening for window disposing
// It's set at our owner frame as component window later too. So it will may be disposed there ...
m_xWindow->addEventListener(static_cast < css::lang::XEventListener* >(this ));
m_xWindow->setVisible(true );
/* } SAFE */
}
void SAL_CALL BackingComp::keyPressed( /*IN*/ const css::awt::KeyEvent& )
{
}
void SAL_CALL BackingComp::keyReleased( /*IN*/ const css::awt::KeyEvent& )
{
/* Attention
Please use keyPressed ( ) instead of this method . Otherwise it would be possible , that
- a key input may be first switch to the backing mode
- and this component register itself as key listener too
- and it ' s first event will be a keyReleased ( ) for the already well known event , which switched to the backing mode !
So it will be handled twice ! document = > backing mode = > exit app . . .
*/
}
// XDispatchProvider
css::uno::Reference< css::frame::XDispatch > SAL_CALL BackingComp::queryDispatch( const css::util::URL& aURL, const OUString& /*sTargetFrameName*/, sal_Int32 /*nSearchFlags*/ )
{
css::uno::Reference< css::frame::XDispatch > xDispatch;
if ( aURL.Protocol == "vnd.org.libreoffice.recentdocs:" )
xDispatch = this ;
return xDispatch;
}
css::uno::Sequence < css::uno::Reference< css::frame::XDispatch > > SAL_CALL BackingComp::queryDispatches( const css::uno::Sequence < css::frame::DispatchDescriptor >& seqDescripts )
{
sal_Int32 nCount = seqDescripts.getLength();
css::uno::Sequence < css::uno::Reference < XDispatch > > lDispatcher( nCount );
std::transform(seqDescripts.begin(), seqDescripts.end(), lDispatcher.getArray(),
[this ](const css::frame::DispatchDescriptor& rDesc) -> css::uno::Reference<XDispatch> {
return queryDispatch(rDesc.FeatureURL, rDesc.FrameName, rDesc.SearchFlags); });
return lDispatcher;
}
// XDispatch
void SAL_CALL BackingComp::dispatch( const css::util::URL& aURL, const css::uno::Sequence < css::beans::PropertyValue >& /*lArgs*/ )
{
// vnd.org.libreoffice.recentdocs:ClearRecentFileList - clear recent files
if ( aURL.Path != "ClearRecentFileList" )
return ;
VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(m_xWindow);
BackingWindow* pBack = dynamic_cast <BackingWindow*>(pWindow.get());
if ( !pBack )
return ;
pBack->clearRecentFileList();
// Recalculate minimum width
css::uno::Reference< css::awt::XWindow > xParentWindow = m_xFrame->getContainerWindow();
VclPtr< WorkWindow > pParent = static_cast <WorkWindow*>(VCLUnoHelper::GetWindow(xParentWindow));
if ( pParent )
{
pParent->SetMinOutputSizePixel( Size(
pBack->get_width_request(),
pParent->GetMinOutputSizePixel().Height()) );
}
}
void SAL_CALL BackingComp::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xControl*/, const css::util::URL& /*aURL*/ )
{
}
void SAL_CALL BackingComp::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xControl*/, const css::util::URL& /*aURL*/ )
{
}
}
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_sfx2_BackingComp_get_implementation(
css::uno::XComponentContext *,
css::uno::Sequence<css::uno::Any> const &)
{
return cppu::acquire(new BackingComp);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=92 H=98 G=94
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland