Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / vcl / source / app / session.cxx
blob2ec3bbc5c7d690f66cf520e8de713064afb7931a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <memory>
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>
28 #include <utility>
29 #include <vcl/svapp.hxx>
31 #include <factory.hxx>
32 #include <svdata.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>
41 #include <vector>
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::lang;
45 using namespace com::sun::star::frame;
47 SalSession::~SalSession()
51 namespace {
53 class VCLSession:
54 public comphelper::WeakComponentImplHelper < XSessionManagerClient, css::lang::XServiceInfo >
56 struct Listener
58 css::uno::Reference< XSessionManagerListener > m_xListener;
59 bool m_bInteractionRequested;
60 bool m_bInteractionDone;
61 bool m_bSaveDone;
63 explicit Listener( css::uno::Reference< XSessionManagerListener > xListener )
64 : m_xListener(std::move( xListener )),
65 m_bInteractionRequested( false ),
66 m_bInteractionDone( false ),
67 m_bSaveDone( 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;
76 bool m_bSaveDone;
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 );
106 void callQuit();
108 public:
109 VCLSession();
114 VCLSession::VCLSession()
115 : m_xSession( ImplGetSVData()->mpDefInst->CreateSalSession() ),
116 m_bInteractionRequested( false ),
117 m_bInteractionGranted( false ),
118 m_bInteractionDone( false ),
119 m_bSaveDone( false )
121 SAL_INFO("vcl.se", "VCLSession::VCLSession" );
123 if (m_xSession)
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
142 m_bSaveDone = false;
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() )
155 if (m_xSession)
156 m_xSession->saveDone();
157 return;
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() )
187 if (m_xSession)
188 m_xSession->interactionDone();
189 return;
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 )
245 case Interaction:
247 SAL_INFO("vcl.se.debug", " EventProcType = Interaction");
248 SalSessionInteractionEvent* pIEv = static_cast<SalSessionInteractionEvent*>(pEvent);
249 pThis->callInteractionGranted( pIEv->m_bInteractionGranted );
251 break;
252 case SaveRequest:
254 SAL_INFO("vcl.se.debug", " EventProcType = SaveRequest");
255 SalSessionSaveRequestEvent* pSEv = static_cast<SalSessionSaveRequestEvent*>(pEvent);
256 pThis->callSaveRequested( pSEv->m_bShutdown );
258 break;
259 case ShutdownCancel:
260 SAL_INFO("vcl.se.debug", " EventProcType = ShutdownCancel");
261 pThis->callShutdownCancelled();
262 break;
263 case Quit:
264 SAL_INFO("vcl.se.debug", " EventProcType = Quit");
265 pThis->callQuit();
266 break;
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;
303 aGuard.unlock();
305 if( bInteractionDone )
306 xListener->approveInteraction( false );
307 else
308 xListener->approveInteraction( true );
309 return;
312 if( ! m_bInteractionRequested )
314 if (m_xSession)
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 )
340 nRequested++;
341 if( xListener == listener.m_xListener )
342 listener.m_bInteractionDone = true;
344 if( listener.m_bInteractionDone )
345 nDone++;
348 SAL_INFO("vcl.se.debug", " nDone = " << nDone <<
349 ", nRequested =" << nRequested);
350 if( nDone == nRequested && nDone > 0 )
352 m_bInteractionDone = true;
353 if (m_xSession)
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 )
370 bSaveDone = false;
373 SAL_INFO("vcl.se.debug", " bSaveDone = " << (bSaveDone ? "true" : "false"));
375 if( bSaveDone && !m_bSaveDone )
377 m_bSaveDone = true;
378 if (m_xSession)
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) {
399 rGuard.unlock();
400 try {
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");
406 rGuard.lock();
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: */