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 <sal/config.h>
22 #include <sal/log.hxx>
24 #include <comphelper/compbase.hxx>
25 #include <cppuhelper/supportsservice.hxx>
27 #include <comphelper/diagnose_ex.hxx>
29 #include <vcl/svapp.hxx>
31 #include <factory.hxx>
33 #include <salinst.hxx>
34 #include <salsession.hxx>
36 #include <com/sun/star/frame/XSessionManagerClient.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/XServiceInfo.hpp>
39 #include <com/sun/star/frame/XSessionManagerListener2.hpp>
43 using namespace com::sun::star::uno
;
44 using namespace com::sun::star::lang
;
45 using namespace com::sun::star::frame
;
47 SalSession::~SalSession()
54 public comphelper::WeakComponentImplHelper
< XSessionManagerClient
, css::lang::XServiceInfo
>
58 css::uno::Reference
< XSessionManagerListener
> m_xListener
;
59 bool m_bInteractionRequested
;
60 bool m_bInteractionDone
;
63 explicit Listener( css::uno::Reference
< XSessionManagerListener
> xListener
)
64 : m_xListener(std::move( xListener
)),
65 m_bInteractionRequested( false ),
66 m_bInteractionDone( false ),
71 std::vector
< Listener
> m_aListeners
;
72 std::unique_ptr
< SalSession
> m_xSession
;
73 bool m_bInteractionRequested
;
74 bool m_bInteractionGranted
;
75 bool m_bInteractionDone
;
78 static void SalSessionEventProc( void* pData
, SalSessionEvent
* pEvent
);
80 virtual ~VCLSession() override
{}
82 virtual void SAL_CALL
addSessionManagerListener( const css::uno::Reference
< XSessionManagerListener
>& xListener
) override
;
83 virtual void SAL_CALL
removeSessionManagerListener( const css::uno::Reference
< XSessionManagerListener
>& xListener
) override
;
84 virtual void SAL_CALL
queryInteraction( const css::uno::Reference
< XSessionManagerListener
>& xListener
) override
;
85 virtual void SAL_CALL
interactionDone( const css::uno::Reference
< XSessionManagerListener
>& xListener
) override
;
86 virtual void SAL_CALL
saveDone( const css::uno::Reference
< XSessionManagerListener
>& xListener
) override
;
87 virtual sal_Bool SAL_CALL
cancelShutdown() override
;
89 OUString SAL_CALL
getImplementationName() override
{
90 return u
"com.sun.star.frame.VCLSessionManagerClient"_ustr
;
93 sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
) override
{
94 return cppu::supportsService(this, ServiceName
);
97 css::uno::Sequence
<OUString
> SAL_CALL
getSupportedServiceNames() override
{
98 return {u
"com.sun.star.frame.SessionManagerClient"_ustr
};
101 void disposing(std::unique_lock
<std::mutex
>& rGuard
) override
;
103 void callSaveRequested( bool bShutdown
);
104 void callShutdownCancelled();
105 void callInteractionGranted( bool bGranted
);
114 VCLSession::VCLSession()
115 : m_xSession( ImplGetSVData()->mpDefInst
->CreateSalSession() ),
116 m_bInteractionRequested( false ),
117 m_bInteractionGranted( false ),
118 m_bInteractionDone( false ),
121 SAL_INFO("vcl.se", "VCLSession::VCLSession" );
124 m_xSession
->SetCallback( SalSessionEventProc
, this );
127 void VCLSession::callSaveRequested( bool bShutdown
)
129 SAL_INFO("vcl.se", "VCLSession::callSaveRequested" );
131 std::vector
< Listener
> aListeners
;
133 std::unique_lock
aGuard( m_aMutex
);
134 // reset listener states
135 for (auto & listener
: m_aListeners
) {
136 listener
.m_bSaveDone
= listener
.m_bInteractionRequested
= listener
.m_bInteractionDone
= false;
139 // copy listener vector since calling a listener may remove it.
140 aListeners
= m_aListeners
;
141 // set back interaction state
143 m_bInteractionDone
= false;
144 // without session we assume UI is always possible,
145 // so it was requested and granted
146 m_bInteractionRequested
= m_bInteractionGranted
= !m_xSession
;
148 // answer the session manager even if no listeners available anymore
149 SAL_WARN_IF( aListeners
.empty(), "vcl.se", "saveRequested but no listeners !" );
151 SAL_INFO("vcl.se.debug", " aListeners.empty() = " << (aListeners
.empty() ? "true" : "false") <<
152 ", bShutdown = " << (bShutdown
? "true" : "false"));
153 if( aListeners
.empty() )
156 m_xSession
->saveDone();
161 SolarMutexReleaser aReleaser
;
162 for (auto const & listener
: aListeners
)
163 listener
.m_xListener
->doSave( bShutdown
, false/*bCancelable*/ );
166 void VCLSession::callInteractionGranted( bool bInteractionGranted
)
168 SAL_INFO("vcl.se", "VCLSession::callInteractionGranted" );
170 std::vector
< Listener
> aListeners
;
172 std::unique_lock
aGuard( m_aMutex
);
173 // copy listener vector since calling a listener may remove it.
174 for (auto const & listener
: m_aListeners
)
175 if( listener
.m_bInteractionRequested
)
176 aListeners
.push_back( listener
);
178 m_bInteractionGranted
= bInteractionGranted
;
180 // answer the session manager even if no listeners available anymore
181 SAL_WARN_IF( aListeners
.empty(), "vcl.se", "interactionGranted but no listeners !" );
183 SAL_INFO("vcl.se.debug", " aListeners.empty() = " << (aListeners
.empty() ? "true" : "false") <<
184 ", bInteractionGranted = " << (bInteractionGranted
? "true" : "false"));
185 if( aListeners
.empty() )
188 m_xSession
->interactionDone();
193 SolarMutexReleaser aReleaser
;
194 for (auto const & listener
: aListeners
)
195 listener
.m_xListener
->approveInteraction( bInteractionGranted
);
198 void VCLSession::callShutdownCancelled()
200 SAL_INFO("vcl.se", "VCLSession::callShutdownCancelled");
202 std::vector
< Listener
> aListeners
;
204 std::unique_lock
aGuard( m_aMutex
);
205 // copy listener vector since calling a listener may remove it.
206 aListeners
= m_aListeners
;
207 // set back interaction state
208 m_bInteractionRequested
= m_bInteractionDone
= m_bInteractionGranted
= false;
211 SolarMutexReleaser aReleaser
;
212 for (auto const & listener
: aListeners
)
213 listener
.m_xListener
->shutdownCanceled();
216 void VCLSession::callQuit()
218 SAL_INFO("vcl.se", "VCLSession::callQuit");
220 std::vector
< Listener
> aListeners
;
222 std::unique_lock
aGuard( m_aMutex
);
223 // copy listener vector since calling a listener may remove it.
224 aListeners
= m_aListeners
;
225 // set back interaction state
226 m_bInteractionRequested
= m_bInteractionDone
= m_bInteractionGranted
= false;
229 SolarMutexReleaser aReleaser
;
230 for (auto const & listener
: aListeners
)
232 css::uno::Reference
< XSessionManagerListener2
> xListener2( listener
.m_xListener
, UNO_QUERY
);
233 if( xListener2
.is() )
234 xListener2
->doQuit();
238 void VCLSession::SalSessionEventProc( void* pData
, SalSessionEvent
* pEvent
)
240 SAL_INFO("vcl.se", "VCLSession::SalSessionEventProc");
242 VCLSession
* pThis
= static_cast< VCLSession
* >( pData
);
243 switch( pEvent
->m_eType
)
247 SAL_INFO("vcl.se.debug", " EventProcType = Interaction");
248 SalSessionInteractionEvent
* pIEv
= static_cast<SalSessionInteractionEvent
*>(pEvent
);
249 pThis
->callInteractionGranted( pIEv
->m_bInteractionGranted
);
254 SAL_INFO("vcl.se.debug", " EventProcType = SaveRequest");
255 SalSessionSaveRequestEvent
* pSEv
= static_cast<SalSessionSaveRequestEvent
*>(pEvent
);
256 pThis
->callSaveRequested( pSEv
->m_bShutdown
);
260 SAL_INFO("vcl.se.debug", " EventProcType = ShutdownCancel");
261 pThis
->callShutdownCancelled();
264 SAL_INFO("vcl.se.debug", " EventProcType = Quit");
270 void SAL_CALL
VCLSession::addSessionManagerListener( const css::uno::Reference
<XSessionManagerListener
>& xListener
)
272 SAL_INFO("vcl.se", "VCLSession::addSessionManagerListener" );
274 std::unique_lock
aGuard( m_aMutex
);
276 SAL_INFO("vcl.se.debug", " m_aListeners.size() = " << m_aListeners
.size() );
277 m_aListeners
.emplace_back( xListener
);
280 void SAL_CALL
VCLSession::removeSessionManagerListener( const css::uno::Reference
<XSessionManagerListener
>& xListener
)
282 SAL_INFO("vcl.se", "VCLSession::removeSessionManagerListener" );
284 std::unique_lock
aGuard( m_aMutex
);
286 SAL_INFO("vcl.se.debug", " m_aListeners.size() = " << m_aListeners
.size() );
288 std::erase_if(m_aListeners
, [&](Listener
& listener
) {return xListener
== listener
.m_xListener
;});
291 void SAL_CALL
VCLSession::queryInteraction( const css::uno::Reference
<XSessionManagerListener
>& xListener
)
293 SAL_INFO("vcl.se", "VCLSession::queryInteraction");
295 SAL_INFO("vcl.se.debug", " m_bInteractionGranted = " << (m_bInteractionGranted
? "true" : "false") <<
296 ", m_bInteractionRequested = "<< (m_bInteractionRequested
? "true" : "false"));
298 std::unique_lock
aGuard( m_aMutex
);
300 if( m_bInteractionGranted
)
302 bool bInteractionDone
= m_bInteractionDone
;
305 if( bInteractionDone
)
306 xListener
->approveInteraction( false );
308 xListener
->approveInteraction( true );
312 if( ! m_bInteractionRequested
)
315 m_xSession
->queryInteraction();
317 m_bInteractionRequested
= true;
319 for (auto & listener
: m_aListeners
)
321 if( listener
.m_xListener
== xListener
)
323 SAL_INFO("vcl.se.debug", " listener.m_xListener == xListener");
324 listener
.m_bInteractionRequested
= true;
325 listener
.m_bInteractionDone
= false;
330 void SAL_CALL
VCLSession::interactionDone( const css::uno::Reference
< XSessionManagerListener
>& xListener
)
332 SAL_INFO("vcl.se", "VCLSession::interactionDone");
334 std::unique_lock
aGuard( m_aMutex
);
335 int nRequested
= 0, nDone
= 0;
336 for (auto & listener
: m_aListeners
)
338 if( listener
.m_bInteractionRequested
)
341 if( xListener
== listener
.m_xListener
)
342 listener
.m_bInteractionDone
= true;
344 if( listener
.m_bInteractionDone
)
348 SAL_INFO("vcl.se.debug", " nDone = " << nDone
<<
349 ", nRequested =" << nRequested
);
350 if( nDone
== nRequested
&& nDone
> 0 )
352 m_bInteractionDone
= true;
354 m_xSession
->interactionDone();
358 void SAL_CALL
VCLSession::saveDone( const css::uno::Reference
< XSessionManagerListener
>& xListener
)
360 SAL_INFO("vcl.se", "VCLSession::saveDone");
362 std::unique_lock
aGuard( m_aMutex
);
364 bool bSaveDone
= true;
365 for (auto & listener
: m_aListeners
)
367 if( listener
.m_xListener
== xListener
)
368 listener
.m_bSaveDone
= true;
369 if( ! listener
.m_bSaveDone
)
373 SAL_INFO("vcl.se.debug", " bSaveDone = " << (bSaveDone
? "true" : "false"));
375 if( bSaveDone
&& !m_bSaveDone
)
379 m_xSession
->saveDone();
383 sal_Bool SAL_CALL
VCLSession::cancelShutdown()
385 SAL_INFO("vcl.se", "VCLSession::cancelShutdown");
387 return m_xSession
&& m_xSession
->cancelShutdown();
390 void VCLSession::disposing(std::unique_lock
<std::mutex
>& rGuard
) {
391 SAL_INFO("vcl.se", "VCLSession::disposing");
393 std::vector
<Listener
> vector
;
395 vector
.swap(m_aListeners
);
397 css::lang::EventObject
src(getXWeak());
398 for (auto const & listener
: vector
) {
401 listener
.m_xListener
->disposing(src
);
402 SAL_INFO("vcl.se.debug", " call Listener disposing");
403 } catch (css::uno::RuntimeException
&) {
404 TOOLS_WARN_EXCEPTION("vcl.se", "ignoring");
410 // service implementation
412 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
413 com_sun_star_frame_VCLSessionManagerClient_get_implementation(
414 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
416 return cppu::acquire(new VCLSession
);
419 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */