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 .
20 #include <services/sessionlistener.hxx>
21 #include <services/desktop.hxx>
22 #include <threadhelp/readguard.hxx>
23 #include <threadhelp/resetableguard.hxx>
24 #include <protocols.h>
27 #include <osl/thread.h>
29 #include <vcl/svapp.hxx>
30 #include <unotools/tempfile.hxx>
31 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
32 #include <com/sun/star/lang/XComponent.hpp>
33 #include <com/sun/star/container/XNameAccess.hpp>
34 #include <com/sun/star/container/XNameContainer.hpp>
35 #include <com/sun/star/beans/NamedValue.hpp>
36 #include <com/sun/star/beans/PropertyValue.hpp>
37 #include <com/sun/star/beans/PropertyState.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/frame/AutoRecovery.hpp>
40 #include <com/sun/star/frame/XFramesSupplier.hpp>
41 #include <com/sun/star/frame/XStorable.hpp>
42 #include <com/sun/star/frame/XComponentLoader.hpp>
43 #include <com/sun/star/frame/XDispatch.hpp>
44 #include <com/sun/star/frame/Desktop.hpp>
45 #include <com/sun/star/util/XModifiable.hpp>
46 #include <com/sun/star/util/XChangesBatch.hpp>
47 #include <com/sun/star/util/URLTransformer.hpp>
48 #include <com/sun/star/util/XURLTransformer.hpp>
49 #include <com/sun/star/util/URL.hpp>
51 #include <comphelper/processfactory.hxx>
52 #include <unotools/pathoptions.hxx>
55 #include <com/sun/star/uno/Any.hxx>
57 #include <com/sun/star/uno/Sequence.hxx>
59 using namespace com::sun::star::uno
;
60 using namespace com::sun::star::util
;
61 using namespace com::sun::star::frame
;
62 using namespace com::sun::star::lang
;
63 using namespace com::sun::star::beans
;
64 using namespace com::sun::star::container
;
69 //***********************************************
70 // XInterface, XTypeProvider, XServiceInfo
75 DIRECT_INTERFACE(css::lang::XTypeProvider
),
76 DIRECT_INTERFACE(css::lang::XInitialization
),
77 DIRECT_INTERFACE(css::frame::XSessionManagerListener
),
78 DIRECT_INTERFACE(css::frame::XSessionManagerListener2
),
79 DIRECT_INTERFACE(css::frame::XStatusListener
),
80 DIRECT_INTERFACE(css::lang::XServiceInfo
))
82 DEFINE_XTYPEPROVIDER_5(
84 css::lang::XTypeProvider
,
85 css::lang::XInitialization
,
86 css::frame::XSessionManagerListener2
,
87 css::frame::XStatusListener
,
88 css::lang::XServiceInfo
)
90 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE(
93 "com.sun.star.frame.SessionListener",
94 IMPLEMENTATIONNAME_SESSIONLISTENER
)
96 DEFINE_INIT_SERVICE(SessionListener
,
98 /* Add special code for initialization here, if you have to use your own instance
99 during your ctor is still in progress! */
103 SessionListener::SessionListener(const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xSMGR
)
104 : ThreadHelpBase (&Application::GetSolarMutex())
107 , m_bRestored( sal_False
)
108 , m_bSessionStoreRequested( sal_False
)
109 , m_bAllowUserInteractionOnQuit( sal_False
)
110 , m_bTerminated( sal_False
)
112 SAL_INFO("fwk.session", "SessionListener::SessionListener");
115 SessionListener::~SessionListener()
117 SAL_INFO("fwk.session", "SessionListener::~SessionListener");
118 if (m_rSessionManager
.is())
120 css::uno::Reference
< XSessionManagerListener
> me(this);
121 m_rSessionManager
->removeSessionManagerListener(me
);
125 void SessionListener::StoreSession( sal_Bool bAsync
)
127 SAL_INFO("fwk.session", "SessionListener::StoreSession");
128 ResetableGuard
aGuard(m_aLock
);
131 // xd create SERVICENAME_AUTORECOVERY -> XDispatch
132 // xd->dispatch("vnd.sun.star.autorecovery:/doSessionSave, async=bAsync
133 // on stop event m_rSessionManager->saveDone(this); in case of asynchronous call
134 // in case of synchronous call the caller should do saveDone() call himself!
136 css::uno::Reference
< XDispatch
> xDispatch
= css::frame::AutoRecovery::create( ::comphelper::getComponentContext(m_xSMGR
) );
137 css::uno::Reference
< XURLTransformer
> xURLTransformer
= URLTransformer::create( ::comphelper::getComponentContext(m_xSMGR
) );
139 aURL
.Complete
= OUString("vnd.sun.star.autorecovery:/doSessionSave");
140 xURLTransformer
->parseStrict(aURL
);
142 // in case of asynchronous call the notification will trigger saveDone()
144 xDispatch
->addStatusListener(this, aURL
);
146 Sequence
< PropertyValue
> args(1);
147 args
[0] = PropertyValue(OUString("DispatchAsynchron"),-1,makeAny(bAsync
),PropertyState_DIRECT_VALUE
);
148 xDispatch
->dispatch(aURL
, args
);
149 } catch (const com::sun::star::uno::Exception
& e
) {
150 SAL_WARN("fwk.session",e
.Message
);
151 // save failed, but tell manager to go on if we havent yet dispatched the request
152 // in case of synchronous saving the notification is done by the caller
153 if ( bAsync
&& m_rSessionManager
.is() )
154 m_rSessionManager
->saveDone(this);
158 void SessionListener::QuitSessionQuietly()
160 SAL_INFO("fwk.session", "SessionListener::QuitSessionQuietly");
161 ResetableGuard
aGuard(m_aLock
);
164 // xd create SERVICENAME_AUTORECOVERY -> XDispatch
165 // xd->dispatch("vnd.sun.star.autorecovery:/doSessionQuietQuit, async=false
166 // it is done synchronously to avoid conflict with normal quit process
168 css::uno::Reference
< XDispatch
> xDispatch
= css::frame::AutoRecovery::create( ::comphelper::getComponentContext(m_xSMGR
) );
169 css::uno::Reference
< XURLTransformer
> xURLTransformer
= URLTransformer::create( ::comphelper::getComponentContext(m_xSMGR
) );
171 aURL
.Complete
= OUString("vnd.sun.star.autorecovery:/doSessionQuietQuit");
172 xURLTransformer
->parseStrict(aURL
);
174 Sequence
< PropertyValue
> args(1);
175 args
[0] = PropertyValue(OUString("DispatchAsynchron"),-1,makeAny(sal_False
),PropertyState_DIRECT_VALUE
);
176 xDispatch
->dispatch(aURL
, args
);
177 } catch (const com::sun::star::uno::Exception
& e
) {
178 SAL_WARN("fwk.session",e
.Message
);
182 void SAL_CALL
SessionListener::disposing(const com::sun::star::lang::EventObject
&) throw (RuntimeException
)
184 SAL_INFO("fwk.session", "SessionListener::disposing");
187 void SAL_CALL
SessionListener::initialize(const Sequence
< Any
>& args
)
188 throw (RuntimeException
)
190 SAL_INFO("fwk.session", "SessionListener::initialize");
192 OUString
aSMgr("com.sun.star.frame.SessionManagerClient");
193 if ( (args
.getLength() == 1) && (args
[0] >>= m_bAllowUserInteractionOnQuit
) )
195 else if (args
.getLength() > 0)
198 for (int i
= 0; i
< args
.getLength(); i
++)
202 if ( v
.Name
== "SessionManagerName" )
204 else if ( v
.Name
== "SessionManager" )
205 v
.Value
>>= m_rSessionManager
;
206 else if ( v
.Name
== "AllowUserInteractionOnQuit" )
207 v
.Value
>>= m_bAllowUserInteractionOnQuit
;
211 if (!m_rSessionManager
.is())
212 m_rSessionManager
= css::uno::Reference
< XSessionManagerClient
>
213 (m_xSMGR
->createInstance(aSMgr
), UNO_QUERY
);
215 if (m_rSessionManager
.is())
217 m_rSessionManager
->addSessionManagerListener(this);
221 void SAL_CALL
SessionListener::statusChanged(const FeatureStateEvent
& event
)
222 throw (css::uno::RuntimeException
)
224 SAL_INFO("fwk.session", "SessionListener::statusChanged");
225 if ( event
.FeatureURL
.Complete
== "vnd.sun.star.autorecovery:/doSessionRestore" )
227 if (event
.FeatureDescriptor
.compareToAscii("update")==0)
228 m_bRestored
= sal_True
; // a document was restored
231 else if ( event
.FeatureURL
.Complete
== "vnd.sun.star.autorecovery:/doSessionSave" )
233 if (event
.FeatureDescriptor
.compareToAscii("stop")==0)
235 if (m_rSessionManager
.is())
236 m_rSessionManager
->saveDone(this); // done with save
242 sal_Bool SAL_CALL
SessionListener::doRestore()
243 throw (RuntimeException
)
245 SAL_INFO("fwk.session", "SessionListener::doRestore");
246 ResetableGuard
aGuard(m_aLock
);
247 m_bRestored
= sal_False
;
249 css::uno::Reference
< XDispatch
> xDispatch
= css::frame::AutoRecovery::create( ::comphelper::getComponentContext(m_xSMGR
) );
252 aURL
.Complete
= OUString("vnd.sun.star.autorecovery:/doSessionRestore");
253 css::uno::Reference
< XURLTransformer
> xURLTransformer(URLTransformer::create(::comphelper::getComponentContext(m_xSMGR
)));
254 xURLTransformer
->parseStrict(aURL
);
255 Sequence
< PropertyValue
> args
;
256 xDispatch
->addStatusListener(this, aURL
);
257 xDispatch
->dispatch(aURL
, args
);
258 m_bRestored
= sal_True
;
260 } catch (const com::sun::star::uno::Exception
& e
) {
261 SAL_WARN("fwk.session",e
.Message
);
268 void SAL_CALL
SessionListener::doSave( sal_Bool bShutdown
, sal_Bool
/*bCancelable*/ )
269 throw (RuntimeException
)
271 SAL_INFO("fwk.session", "SessionListener::doSave");
274 m_bSessionStoreRequested
= sal_True
; // there is no need to protect it with mutex
275 if ( m_bAllowUserInteractionOnQuit
&& m_rSessionManager
.is() )
276 m_rSessionManager
->queryInteraction( static_cast< css::frame::XSessionManagerListener
* >( this ) );
278 StoreSession( sal_True
);
280 // we don't have anything to do so tell the session manager we're done
281 else if( m_rSessionManager
.is() )
282 m_rSessionManager
->saveDone( this );
285 void SAL_CALL
SessionListener::approveInteraction( sal_Bool bInteractionGranted
)
286 throw (RuntimeException
)
288 SAL_INFO("fwk.session", "SessionListener::approveInteraction");
289 // do AutoSave as the first step
290 ResetableGuard
aGuard(m_aLock
);
292 if ( bInteractionGranted
)
294 // close the office documents in normal way
297 // first of all let the session be stored to be sure that we lose no information
298 StoreSession( sal_False
);
300 css::uno::Reference
< css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create( comphelper::getComponentContext(m_xSMGR
) );
301 // honestly: how many implementations of XDesktop will we ever have?
302 // so casting this directly to the implementation
303 Desktop
* pDesktop(dynamic_cast<Desktop
*>(xDesktop
.get()));
306 SAL_INFO("fwk.session", "XDesktop is a framework::Desktop -- good.");
307 m_bTerminated
= pDesktop
->terminateQuickstarterToo();
311 SAL_WARN("fwk.session", "XDesktop is not a framework::Desktop -- this should never happen.");
312 m_bTerminated
= xDesktop
->terminate();
315 if ( m_rSessionManager
.is() )
317 // false means that the application closing has been cancelled
318 if ( !m_bTerminated
)
319 m_rSessionManager
->cancelShutdown();
321 m_rSessionManager
->interactionDone( this );
324 catch( const css::uno::Exception
& )
326 StoreSession( sal_True
);
327 m_rSessionManager
->interactionDone( this );
330 if ( m_rSessionManager
.is() )
331 m_rSessionManager
->saveDone(this);
335 StoreSession( sal_True
);
339 void SessionListener::shutdownCanceled()
340 throw (RuntimeException
)
342 SAL_INFO("fwk.session", "SessionListener::shutdownCanceled");
343 // set the state back
344 m_bSessionStoreRequested
= sal_False
; // there is no need to protect it with mutex
347 void SessionListener::doQuit()
348 throw (RuntimeException
)
350 SAL_INFO("fwk.session", "SessionListener::doQuit");
351 if ( m_bSessionStoreRequested
&& !m_bTerminated
)
353 // let the session be closed quietly in this case
354 QuitSessionQuietly();
360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */