LibreOffice Module vcl (master)  1
session.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <sal/config.h>
22 #include <sal/log.hxx>
23 
24 #include <cppuhelper/basemutex.hxx>
25 #include <cppuhelper/compbase.hxx>
26 
27 #include <tools/diagnose_ex.h>
28 #include <vcl/svapp.hxx>
29 
30 #include <factory.hxx>
31 #include <svdata.hxx>
32 #include <salinst.hxx>
33 #include <salsession.hxx>
34 
35 #include <com/sun/star/frame/XSessionManagerClient.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/frame/XSessionManagerListener2.hpp>
38 
39 #include <vector>
40 
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::lang;
43 using namespace com::sun::star::frame;
44 
46 {
47 }
48 
49 class VCLSession:
50  private cppu::BaseMutex,
51  public cppu::WeakComponentImplHelper < XSessionManagerClient >
52 {
53  struct Listener
54  {
55  css::uno::Reference< XSessionManagerListener > m_xListener;
59 
60  explicit Listener( const css::uno::Reference< XSessionManagerListener >& xListener )
61  : m_xListener( xListener ),
62  m_bInteractionRequested( false ),
63  m_bInteractionDone( false ),
64  m_bSaveDone( false )
65  {}
66  };
67 
68  std::vector< Listener > m_aListeners;
69  std::unique_ptr< SalSession > m_xSession;
74 
75  static void SalSessionEventProc( void* pData, SalSessionEvent* pEvent );
76 
77  virtual ~VCLSession() override {}
78 
79  virtual void SAL_CALL addSessionManagerListener( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
80  virtual void SAL_CALL removeSessionManagerListener( const css::uno::Reference< XSessionManagerListener>& xListener ) override;
81  virtual void SAL_CALL queryInteraction( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
82  virtual void SAL_CALL interactionDone( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
83  virtual void SAL_CALL saveDone( const css::uno::Reference< XSessionManagerListener >& xListener ) override;
84  virtual sal_Bool SAL_CALL cancelShutdown() override;
85 
86  void SAL_CALL disposing() override;
87 
88  void callSaveRequested( bool bShutdown );
89  void callShutdownCancelled();
90  void callInteractionGranted( bool bGranted );
91  void callQuit();
92 
93 public:
94  VCLSession();
95 };
96 
98  : cppu::WeakComponentImplHelper< XSessionManagerClient >( m_aMutex ),
99  m_xSession( ImplGetSVData()->mpDefInst->CreateSalSession() ),
100  m_bInteractionRequested( false ),
101  m_bInteractionGranted( false ),
102  m_bInteractionDone( false ),
103  m_bSaveDone( false )
104 {
105  SAL_INFO("vcl.se", "VCLSession::VCLSession" );
106 
107  if (m_xSession)
108  m_xSession->SetCallback( SalSessionEventProc, this );
109 }
110 
111 void VCLSession::callSaveRequested( bool bShutdown )
112 {
113  SAL_INFO("vcl.se", "VCLSession::callSaveRequested" );
114 
115  std::vector< Listener > aListeners;
116  {
117  osl::MutexGuard aGuard( m_aMutex );
118  // reset listener states
119  for (auto & listener : m_aListeners) {
120  listener.m_bSaveDone = listener.m_bInteractionRequested = listener.m_bInteractionDone = false;
121  }
122 
123  // copy listener vector since calling a listener may remove it.
124  aListeners = m_aListeners;
125  // set back interaction state
126  m_bSaveDone = false;
127  m_bInteractionDone = false;
128  // without session we assume UI is always possible,
129  // so it was requested and granted
131 
132  // answer the session manager even if no listeners available anymore
133  SAL_WARN_IF( aListeners.empty(), "vcl.se", "saveRequested but no listeners !" );
134 
135  SAL_INFO("vcl.se.debug", " aListeners.empty() = " << (aListeners.empty() ? "true" : "false") <<
136  ", bShutdown = " << (bShutdown ? "true" : "false"));
137  if( aListeners.empty() )
138  {
139  if (m_xSession)
140  m_xSession->saveDone();
141  return;
142  }
143  }
144 
145  SolarMutexReleaser aReleaser;
146  for (auto const & listener: aListeners)
147  listener.m_xListener->doSave( bShutdown, false/*bCancelable*/ );
148 }
149 
150 void VCLSession::callInteractionGranted( bool bInteractionGranted )
151 {
152  SAL_INFO("vcl.se", "VCLSession::callInteractionGranted" );
153 
154  std::vector< Listener > aListeners;
155  {
156  osl::MutexGuard aGuard( m_aMutex );
157  // copy listener vector since calling a listener may remove it.
158  for (auto const & listener: m_aListeners)
159  if( listener.m_bInteractionRequested )
160  aListeners.push_back( listener );
161 
162  m_bInteractionGranted = bInteractionGranted;
163 
164  // answer the session manager even if no listeners available anymore
165  SAL_WARN_IF( aListeners.empty(), "vcl.se", "interactionGranted but no listeners !" );
166 
167  SAL_INFO("vcl.se.debug", " aListeners.empty() = " << (aListeners.empty() ? "true" : "false") <<
168  ", bInteractionGranted = " << (bInteractionGranted ? "true" : "false"));
169  if( aListeners.empty() )
170  {
171  if (m_xSession)
172  m_xSession->interactionDone();
173  return;
174  }
175  }
176 
177  SolarMutexReleaser aReleaser;
178  for (auto const & listener: aListeners)
179  listener.m_xListener->approveInteraction( bInteractionGranted );
180 }
181 
183 {
184  SAL_INFO("vcl.se", "VCLSession::callShutdownCancelled");
185 
186  std::vector< Listener > aListeners;
187  {
188  osl::MutexGuard aGuard( m_aMutex );
189  // copy listener vector since calling a listener may remove it.
190  aListeners = m_aListeners;
191  // set back interaction state
193  }
194 
195  SolarMutexReleaser aReleaser;
196  for (auto const & listener: aListeners)
197  listener.m_xListener->shutdownCanceled();
198 }
199 
201 {
202  SAL_INFO("vcl.se", "VCLSession::callQuit");
203 
204  std::vector< Listener > aListeners;
205  {
206  osl::MutexGuard aGuard( m_aMutex );
207  // copy listener vector since calling a listener may remove it.
208  aListeners = m_aListeners;
209  // set back interaction state
211  }
212 
213  SolarMutexReleaser aReleaser;
214  for (auto const & listener: aListeners)
215  {
216  css::uno::Reference< XSessionManagerListener2 > xListener2( listener.m_xListener, UNO_QUERY );
217  if( xListener2.is() )
218  xListener2->doQuit();
219  }
220 }
221 
223 {
224  SAL_INFO("vcl.se", "VCLSession::SalSessionEventProc");
225 
226  VCLSession * pThis = static_cast< VCLSession * >( pData );
227  switch( pEvent->m_eType )
228  {
229  case Interaction:
230  {
231  SAL_INFO("vcl.se.debug", " EventProcType = Interaction");
232  SalSessionInteractionEvent* pIEv = static_cast<SalSessionInteractionEvent*>(pEvent);
234  }
235  break;
236  case SaveRequest:
237  {
238  SAL_INFO("vcl.se.debug", " EventProcType = SaveRequest");
239  SalSessionSaveRequestEvent* pSEv = static_cast<SalSessionSaveRequestEvent*>(pEvent);
240  pThis->callSaveRequested( pSEv->m_bShutdown );
241  }
242  break;
243  case ShutdownCancel:
244  SAL_INFO("vcl.se.debug", " EventProcType = ShutdownCancel");
245  pThis->callShutdownCancelled();
246  break;
247  case Quit:
248  SAL_INFO("vcl.se.debug", " EventProcType = Quit");
249  pThis->callQuit();
250  break;
251  }
252 }
253 
254 void SAL_CALL VCLSession::addSessionManagerListener( const css::uno::Reference<XSessionManagerListener>& xListener )
255 {
256  SAL_INFO("vcl.se", "VCLSession::addSessionManagerListener" );
257 
258  osl::MutexGuard aGuard( m_aMutex );
259 
260  SAL_INFO("vcl.se.debug", " m_aListeners.size() = " << m_aListeners.size() );
261  m_aListeners.emplace_back( xListener );
262 }
263 
264 void SAL_CALL VCLSession::removeSessionManagerListener( const css::uno::Reference<XSessionManagerListener>& xListener )
265 {
266  SAL_INFO("vcl.se", "VCLSession::removeSessionManagerListener" );
267 
268  osl::MutexGuard aGuard( m_aMutex );
269 
270  SAL_INFO("vcl.se.debug", " m_aListeners.size() = " << m_aListeners.size() );
271 
272  m_aListeners.erase(std::remove_if(m_aListeners.begin(), m_aListeners.end(), [&](Listener& listener) {return xListener == listener.m_xListener;}), m_aListeners.end());
273 }
274 
275 void SAL_CALL VCLSession::queryInteraction( const css::uno::Reference<XSessionManagerListener>& xListener )
276 {
277  SAL_INFO("vcl.se", "VCLSession::queryInteraction");
278 
279  SAL_INFO("vcl.se.debug", " m_bInteractionGranted = " << (m_bInteractionGranted ? "true" : "false") <<
280  ", m_bInteractionRequested = "<< (m_bInteractionRequested ? "true" : "false"));
282  {
283  if( m_bInteractionDone )
284  xListener->approveInteraction( false );
285  else
286  xListener->approveInteraction( true );
287  return;
288  }
289 
290  osl::MutexGuard aGuard( m_aMutex );
292  {
293  m_xSession->queryInteraction();
295  }
296  for (auto & listener: m_aListeners)
297  {
298  if( listener.m_xListener == xListener )
299  {
300  SAL_INFO("vcl.se.debug", " listener.m_xListener == xListener");
301  listener.m_bInteractionRequested = true;
302  listener.m_bInteractionDone = false;
303  }
304  }
305 }
306 
307 void SAL_CALL VCLSession::interactionDone( const css::uno::Reference< XSessionManagerListener >& xListener )
308 {
309  SAL_INFO("vcl.se", "VCLSession::interactionDone");
310 
311  osl::MutexGuard aGuard( m_aMutex );
312  int nRequested = 0, nDone = 0;
313  for (auto & listener: m_aListeners)
314  {
315  if( listener.m_bInteractionRequested )
316  {
317  nRequested++;
318  if( xListener == listener.m_xListener )
319  listener.m_bInteractionDone = true;
320  }
321  if( listener.m_bInteractionDone )
322  nDone++;
323  }
324 
325  SAL_INFO("vcl.se.debug", " nDone = " << nDone <<
326  ", nRequested =" << nRequested);
327  if( nDone == nRequested && nDone > 0 )
328  {
329  m_bInteractionDone = true;
330  if (m_xSession)
331  m_xSession->interactionDone();
332  }
333 }
334 
335 void SAL_CALL VCLSession::saveDone( const css::uno::Reference< XSessionManagerListener >& xListener )
336 {
337  SAL_INFO("vcl.se", "VCLSession::saveDone");
338 
339  osl::MutexGuard aGuard( m_aMutex );
340 
341  bool bSaveDone = true;
342  for (auto & listener: m_aListeners)
343  {
344  if( listener.m_xListener == xListener )
345  listener.m_bSaveDone = true;
346  if( ! listener.m_bSaveDone )
347  bSaveDone = false;
348  }
349 
350  SAL_INFO("vcl.se.debug", " bSaveDone = " << (bSaveDone ? "true" : "false"));
351 
352  if( bSaveDone && !m_bSaveDone )
353  {
354  m_bSaveDone = true;
355  if (m_xSession)
356  m_xSession->saveDone();
357  }
358 }
359 
361 {
362  SAL_INFO("vcl.se", "VCLSession::cancelShutdown");
363 
364  return m_xSession && m_xSession->cancelShutdown();
365 }
366 
368  SAL_INFO("vcl.se", "VCLSession::disposing");
369 
370  std::vector<Listener> vector;
371  {
372  osl::MutexGuard g(m_aMutex);
373  vector.swap(m_aListeners);
374  }
375  css::lang::EventObject src(static_cast<OWeakObject *>(this));
376  for (auto const & listener: vector) {
377  try {
378  listener.m_xListener->disposing(src);
379  SAL_INFO("vcl.se.debug", " call Listener disposing");
380  } catch (css::uno::RuntimeException &) {
381  TOOLS_WARN_EXCEPTION("vcl.se", "ignoring");
382  }
383  }
384 }
385 
386 // service implementation
387 
389 {
390  SAL_INFO("vcl.se", "vcl_session_getImplementationName");
391 
392  return "com.sun.star.frame.VCLSessionManagerClient";
393 }
394 
396 {
397  SAL_INFO("vcl.se", "vcl_session_getSupportedServiceNames");
398 
399  Sequence< OUString > aRet { "com.sun.star.frame.SessionManagerClient" };
400  return aRet;
401 }
402 
403 css::uno::Reference< XInterface > vcl_session_createInstance( SAL_UNUSED_PARAMETER const css::uno::Reference< XMultiServiceFactory > & )
404 {
405  SAL_INFO("vcl.se", "vcl_session_createInstance");
406 
407  return static_cast< cppu::OWeakObject * >(new VCLSession);
408 }
409 
410 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::osl::Mutex m_aMutex
bool m_bInteractionGranted
Definition: session.cxx:71
virtual ~SalSession()
Definition: session.cxx:45
virtual void SAL_CALL queryInteraction(const css::uno::Reference< XSessionManagerListener > &xListener) override
Definition: session.cxx:275
bool m_bInteractionRequested
Definition: session.cxx:70
bool m_bInteractionRequested
Definition: session.cxx:56
bool m_bSaveDone
Definition: session.cxx:73
mutable::osl::Mutex m_aMutex
bool const m_bInteractionGranted
Definition: salsession.hxx:44
void callShutdownCancelled()
Definition: session.cxx:182
css::uno::Reference< XInterface > vcl_session_createInstance(SAL_UNUSED_PARAMETER const css::uno::Reference< XMultiServiceFactory > &)
Definition: session.cxx:403
bool m_bInteractionDone
Definition: session.cxx:72
virtual ~VCLSession() override
Definition: session.cxx:77
A helper class that calls Application::ReleaseSolarMutex() in its constructor and restores the mutex ...
Definition: svapp.hxx:1433
Listener(const css::uno::Reference< XSessionManagerListener > &xListener)
Definition: session.cxx:60
Listeners aListeners
virtual void SAL_CALL interactionDone(const css::uno::Reference< XSessionManagerListener > &xListener) override
Definition: session.cxx:307
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:67
void SAL_CALL disposing() override
Definition: session.cxx:367
#define TOOLS_WARN_EXCEPTION(area, stream)
void callQuit()
Definition: session.cxx:200
Sequence< OUString > vcl_session_getSupportedServiceNames()
Definition: session.cxx:395
void callSaveRequested(bool bShutdown)
Definition: session.cxx:111
unsigned char sal_Bool
css::uno::Reference< XSessionManagerListener > m_xListener
Definition: session.cxx:55
VCLSession()
Definition: session.cxx:97
virtual void SAL_CALL addSessionManagerListener(const css::uno::Reference< XSessionManagerListener > &xListener) override
Definition: session.cxx:254
SalSessionEventType const m_eType
Definition: salsession.hxx:35
#define SAL_WARN_IF(condition, area, stream)
virtual sal_Bool SAL_CALL cancelShutdown() override
Definition: session.cxx:360
OUString vcl_session_getImplementationName()
Definition: session.cxx:388
static void SalSessionEventProc(void *pData, SalSessionEvent *pEvent)
Definition: session.cxx:222
#define SAL_INFO(area, stream)
virtual void SAL_CALL removeSessionManagerListener(const css::uno::Reference< XSessionManagerListener > &xListener) override
Definition: session.cxx:264
virtual void SAL_CALL saveDone(const css::uno::Reference< XSessionManagerListener > &xListener) override
Definition: session.cxx:335
std::vector< Listener > m_aListeners
Definition: session.cxx:68
void callInteractionGranted(bool bGranted)
Definition: session.cxx:150
std::unique_ptr< SalSession > m_xSession
Definition: session.cxx:69