1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <cppuhelper/supportsservice.hxx>
23 #include <com/sun/star/util/CloseVetoException.hpp>
24 #include <com/sun/star/util/XCloseBroadcaster.hpp>
25 #include <com/sun/star/util/XCloseable.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/lang/IllegalArgumentException.hpp>
28 #include <com/sun/star/frame/XDesktop.hpp>
29 #include <com/sun/star/frame/TerminationVetoException.hpp>
30 #include <com/sun/star/frame/DoubleInitializationException.hpp>
31 #include <com/sun/star/embed/Actions.hpp>
32 #include <com/sun/star/embed/XActionsApproval.hpp>
35 #include "instancelocker.hxx"
37 namespace com::sun::star::uno
{ class XComponentContext
; }
39 using namespace ::com::sun::star
;
45 OInstanceLocker::OInstanceLocker()
46 : m_bDisposed( false )
47 , m_bInitialized( false )
52 OInstanceLocker::~OInstanceLocker()
56 osl_atomic_increment(&m_refCount
); // to call dispose
60 catch ( uno::RuntimeException
& )
67 void SAL_CALL
OInstanceLocker::dispose()
69 std::unique_lock
aGuard( m_aMutex
);
72 throw lang::DisposedException();
74 lang::EventObject
aSource( static_cast< ::cppu::OWeakObject
* >(this) );
75 m_aListenersContainer
.disposeAndClear( aGuard
, aSource
);
76 if ( m_xLockListener
.is() )
78 auto tmp
= std::move(m_xLockListener
);
88 void SAL_CALL
OInstanceLocker::addEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
90 std::unique_lock
aGuard( m_aMutex
);
92 throw lang::DisposedException(); // TODO
94 m_aListenersContainer
.addInterface( aGuard
, xListener
);
98 void SAL_CALL
OInstanceLocker::removeEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
100 std::unique_lock
aGuard( m_aMutex
);
101 m_aListenersContainer
.removeInterface( aGuard
, xListener
);
106 void SAL_CALL
OInstanceLocker::initialize( const uno::Sequence
< uno::Any
>& aArguments
)
108 std::unique_lock
aGuard( m_aMutex
);
109 if ( m_bInitialized
)
110 throw frame::DoubleInitializationException();
113 throw lang::DisposedException(); // TODO
116 throw uno::RuntimeException(); // the object must be refcounted already!
118 uno::Reference
< uno::XInterface
> xInstance
;
119 uno::Reference
< embed::XActionsApproval
> xApproval
;
123 sal_Int32 nLen
= aArguments
.getLength();
124 if ( nLen
< 2 || nLen
> 3 )
125 throw lang::IllegalArgumentException(
126 "Wrong count of parameters!",
127 uno::Reference
< uno::XInterface
>(),
130 if ( !( aArguments
[0] >>= xInstance
) || !xInstance
.is() )
131 throw lang::IllegalArgumentException(
132 "Nonempty reference is expected as the first argument!",
133 uno::Reference
< uno::XInterface
>(),
136 sal_Int32 nModes
= 0;
138 !( aArguments
[1] >>= nModes
) ||
140 !( nModes
& embed::Actions::PREVENT_CLOSE
) &&
141 !( nModes
& embed::Actions::PREVENT_TERMINATION
)
145 throw lang::IllegalArgumentException(
146 "The correct modes set is expected as the second argument!",
147 uno::Reference
< uno::XInterface
>(),
151 if ( nLen
== 3 && !( aArguments
[2] >>= xApproval
) )
152 throw lang::IllegalArgumentException(
153 "If the third argument is provided, it must be XActionsApproval implementation!",
154 uno::Reference
< uno::XInterface
>(),
157 m_xLockListener
= new OLockListener( uno::Reference
< lang::XComponent
> ( static_cast< lang::XComponent
* >( this ) ),
161 m_xLockListener
->Init();
163 catch( uno::Exception
& )
170 m_bInitialized
= true;
174 OUString SAL_CALL
OInstanceLocker::getImplementationName( )
176 return "com.sun.star.comp.embed.InstanceLocker";
179 sal_Bool SAL_CALL
OInstanceLocker::supportsService( const OUString
& ServiceName
)
181 return cppu::supportsService(this, ServiceName
);
184 uno::Sequence
< OUString
> SAL_CALL
OInstanceLocker::getSupportedServiceNames()
186 return { "com.sun.star.embed.InstanceLocker" };
192 OLockListener::OLockListener( uno::WeakReference
< lang::XComponent
> xWrapper
,
193 uno::Reference
< uno::XInterface
> xInstance
,
195 uno::Reference
< embed::XActionsApproval
> xApproval
)
196 : m_xInstance(std::move( xInstance
))
197 , m_xApproval(std::move( xApproval
))
198 , m_xWrapper(std::move( xWrapper
))
199 , m_bDisposed( false )
200 , m_bInitialized( false )
206 OLockListener::~OLockListener()
211 void OLockListener::Dispose()
213 std::unique_lock
aGuard( m_aMutex
);
218 auto xInstance
= std::move(m_xInstance
);
219 auto nMode
= m_nMode
;
223 if ( nMode
& embed::Actions::PREVENT_CLOSE
)
227 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( xInstance
, uno::UNO_QUERY
);
228 if ( xCloseBroadcaster
.is() )
229 xCloseBroadcaster
->removeCloseListener( static_cast< util::XCloseListener
* >( this ) );
231 uno::Reference
< util::XCloseable
> xCloseable( xInstance
, uno::UNO_QUERY
);
232 if ( xCloseable
.is() )
233 xCloseable
->close( true );
235 catch( uno::Exception
& )
239 if ( nMode
& embed::Actions::PREVENT_TERMINATION
)
243 uno::Reference
< frame::XDesktop
> xDesktop( xInstance
, uno::UNO_QUERY_THROW
);
244 xDesktop
->removeTerminateListener( static_cast< frame::XTerminateListener
* >( this ) );
246 catch( uno::Exception
& )
253 void SAL_CALL
OLockListener::disposing( const lang::EventObject
& aEvent
)
255 std::unique_lock
aGuard( m_aMutex
);
257 // object is disposed
258 if ( aEvent
.Source
!= m_xInstance
)
261 // the object does not listen for anything any more
264 // dispose the wrapper;
265 uno::Reference
< lang::XComponent
> xComponent( m_xWrapper
.get(), uno::UNO_QUERY
);
267 if ( xComponent
.is() )
269 try { xComponent
->dispose(); }
270 catch( uno::Exception
& ){}
277 void SAL_CALL
OLockListener::queryClosing( const lang::EventObject
& aEvent
, sal_Bool
)
279 // GetsOwnership parameter is always ignored, the user of the service must close the object always
280 std::unique_lock
aGuard( m_aMutex
);
281 if ( !(!m_bDisposed
&& aEvent
.Source
== m_xInstance
&& ( m_nMode
& embed::Actions::PREVENT_CLOSE
)) )
286 uno::Reference
< embed::XActionsApproval
> xApprove
= m_xApproval
;
288 // unlock the mutex here
291 if ( xApprove
.is() && xApprove
->approveAction( embed::Actions::PREVENT_CLOSE
) )
292 throw util::CloseVetoException();
294 catch( util::CloseVetoException
& )
296 // rethrow this exception
299 catch( uno::Exception
& )
301 // no action should be done
306 void SAL_CALL
OLockListener::notifyClosing( const lang::EventObject
& aEvent
)
308 std::unique_lock
aGuard( m_aMutex
);
310 // object is closed, no reason to listen
311 if ( aEvent
.Source
!= m_xInstance
)
314 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( aEvent
.Source
, uno::UNO_QUERY
);
315 if ( !xCloseBroadcaster
.is() )
318 xCloseBroadcaster
->removeCloseListener( static_cast< util::XCloseListener
* >( this ) );
319 m_nMode
&= ~embed::Actions::PREVENT_CLOSE
;
322 // dispose the wrapper;
323 uno::Reference
< lang::XComponent
> xComponent( m_xWrapper
.get(), uno::UNO_QUERY
);
325 if ( xComponent
.is() )
327 try { xComponent
->dispose(); }
328 catch( uno::Exception
& ){}
334 // XTerminateListener
336 void SAL_CALL
OLockListener::queryTermination( const lang::EventObject
& aEvent
)
338 std::unique_lock
aGuard( m_aMutex
);
339 if ( !(aEvent
.Source
== m_xInstance
&& ( m_nMode
& embed::Actions::PREVENT_TERMINATION
)) )
344 uno::Reference
< embed::XActionsApproval
> xApprove
= m_xApproval
;
346 // unlock the mutex here
349 if ( xApprove
.is() && xApprove
->approveAction( embed::Actions::PREVENT_TERMINATION
) )
350 throw frame::TerminationVetoException();
352 catch( frame::TerminationVetoException
& )
354 // rethrow this exception
357 catch( uno::Exception
& )
359 // no action should be done
364 void SAL_CALL
OLockListener::notifyTermination( const lang::EventObject
& aEvent
)
366 std::unique_lock
aGuard( m_aMutex
);
368 // object is terminated, no reason to listen
369 if ( aEvent
.Source
!= m_xInstance
)
372 uno::Reference
< frame::XDesktop
> xDesktop( aEvent
.Source
, uno::UNO_QUERY
);
373 if ( !xDesktop
.is() )
378 xDesktop
->removeTerminateListener( static_cast< frame::XTerminateListener
* >( this ) );
379 m_nMode
&= ~embed::Actions::PREVENT_TERMINATION
;
382 // dispose the wrapper;
383 uno::Reference
< lang::XComponent
> xComponent( m_xWrapper
.get(), uno::UNO_QUERY
);
385 if ( xComponent
.is() )
387 try { xComponent
->dispose(); }
388 catch( uno::Exception
& ){}
392 catch( uno::Exception
& )
399 void OLockListener::Init()
401 std::unique_lock
aGuard( m_aMutex
);
403 if ( m_bDisposed
|| m_bInitialized
)
408 if ( m_nMode
& embed::Actions::PREVENT_CLOSE
)
410 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( m_xInstance
, uno::UNO_QUERY_THROW
);
411 xCloseBroadcaster
->addCloseListener( static_cast< util::XCloseListener
* >( this ) );
414 if ( m_nMode
& embed::Actions::PREVENT_TERMINATION
)
416 uno::Reference
< frame::XDesktop
> xDesktop( m_xInstance
, uno::UNO_QUERY_THROW
);
417 xDesktop
->addTerminateListener( static_cast< frame::XTerminateListener
* >( this ) );
420 catch( uno::Exception
& )
422 // dispose the wrapper;
423 uno::Reference
< lang::XComponent
> xComponent( m_xWrapper
.get(), uno::UNO_QUERY
);
425 if ( xComponent
.is() )
427 try { xComponent
->dispose(); }
428 catch( uno::Exception
& ){}
434 m_bInitialized
= true;
437 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
438 com_sun_star_comp_embed_InstanceLocker(
439 css::uno::XComponentContext
*,
440 css::uno::Sequence
<css::uno::Any
> const &)
442 return cppu::acquire(new OInstanceLocker());
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */