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