1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <cppuhelper/compbase1.hxx> 28 29 #include <tools/debug.hxx> 30 31 #include <vcl/svapp.hxx> 32 33 #include <svdata.hxx> 34 #include <salinst.hxx> 35 #include <salsession.hxx> 36 37 #include <com/sun/star/frame/XSessionManagerClient.hpp> 38 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 39 #include <com/sun/star/frame/XSessionManagerListener2.hpp> 40 41 #include <list> 42 43 namespace { 44 45 namespace css = com::sun::star; 46 47 } 48 49 using namespace com::sun::star::uno; 50 using namespace com::sun::star::lang; 51 using namespace com::sun::star::frame; 52 using namespace rtl; 53 54 SalSession::~SalSession() 55 { 56 } 57 58 class VCLSession : public cppu::WeakComponentImplHelper1 < XSessionManagerClient > 59 { 60 struct Listener 61 { 62 css::uno::Reference< XSessionManagerListener > m_xListener; 63 bool m_bInteractionRequested; 64 bool m_bInteractionDone; 65 bool m_bSaveDone; 66 67 Listener( const css::uno::Reference< XSessionManagerListener >& xListener ) 68 : m_xListener( xListener ), 69 m_bInteractionRequested( false ), 70 m_bInteractionDone( false ), 71 m_bSaveDone( false ) 72 {} 73 }; 74 75 std::list< Listener > m_aListeners; 76 SalSession* m_pSession; 77 osl::Mutex m_aMutex; 78 bool m_bInteractionRequested; 79 bool m_bInteractionGranted; 80 bool m_bInteractionDone; 81 bool m_bSaveDone; 82 83 static void SalSessionEventProc( SalSessionEvent* pEvent ); 84 static VCLSession* pOneInstance; 85 86 void callSaveRequested( bool bShutdown, bool bCancelable ); 87 void callShutdownCancelled(); 88 void callInteractionGranted( bool bGranted ); 89 void callQuit(); 90 public: 91 VCLSession(); 92 virtual ~VCLSession(); 93 94 virtual void SAL_CALL addSessionManagerListener( const css::uno::Reference< XSessionManagerListener >& xListener ) throw( RuntimeException ); 95 virtual void SAL_CALL removeSessionManagerListener( const css::uno::Reference< XSessionManagerListener>& xListener ) throw( RuntimeException ); 96 virtual void SAL_CALL queryInteraction( const css::uno::Reference< XSessionManagerListener >& xListener ) throw( RuntimeException ); 97 virtual void SAL_CALL interactionDone( const css::uno::Reference< XSessionManagerListener >& xListener ) throw( RuntimeException ); 98 virtual void SAL_CALL saveDone( const css::uno::Reference< XSessionManagerListener >& xListener ) throw( RuntimeException ); 99 virtual sal_Bool SAL_CALL cancelShutdown() throw( RuntimeException ); 100 }; 101 102 VCLSession* VCLSession::pOneInstance = NULL; 103 104 VCLSession::VCLSession() 105 : cppu::WeakComponentImplHelper1< XSessionManagerClient >( m_aMutex ), 106 m_bInteractionRequested( false ), 107 m_bInteractionGranted( false ), 108 m_bInteractionDone( false ), 109 m_bSaveDone( false ) 110 { 111 DBG_ASSERT( pOneInstance == 0, "One instance of VCLSession only !" ); 112 pOneInstance = this; 113 m_pSession = ImplGetSVData()->mpDefInst->CreateSalSession(); 114 if( m_pSession ) 115 m_pSession->SetCallback( SalSessionEventProc ); 116 } 117 118 VCLSession::~VCLSession() 119 { 120 DBG_ASSERT( pOneInstance == this, "Another instance of VCLSession in destructor !" ); 121 pOneInstance = NULL; 122 delete m_pSession; 123 } 124 125 void VCLSession::callSaveRequested( bool bShutdown, bool bCancelable ) 126 { 127 std::list< Listener > aListeners; 128 { 129 osl::MutexGuard aGuard( m_aMutex ); 130 // reset listener states 131 for( std::list< Listener >::iterator it = m_aListeners.begin(); 132 it != m_aListeners.end(); ++it ) 133 { 134 it->m_bSaveDone = it->m_bInteractionRequested = it->m_bInteractionDone = false; 135 } 136 137 // copy listener list since calling a listener may remove it. 138 aListeners = m_aListeners; 139 // set back interaction state 140 m_bSaveDone = false; 141 m_bInteractionDone = false; 142 // without session we assume UI is always possible, 143 // so it was reqeusted and granted 144 m_bInteractionRequested = m_bInteractionGranted = m_pSession ? false : true; 145 146 // answer the session manager even if no listeners available anymore 147 DBG_ASSERT( ! aListeners.empty(), "saveRequested but no listeners !" ); 148 if( aListeners.empty() ) 149 { 150 if( m_pSession ) 151 m_pSession->saveDone(); 152 return; 153 } 154 } 155 156 sal_uLong nAcquireCount = Application::ReleaseSolarMutex(); 157 for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it ) 158 it->m_xListener->doSave( bShutdown, bCancelable ); 159 Application::AcquireSolarMutex( nAcquireCount ); 160 } 161 162 void VCLSession::callInteractionGranted( bool bInteractionGranted ) 163 { 164 std::list< Listener > aListeners; 165 { 166 osl::MutexGuard aGuard( m_aMutex ); 167 // copy listener list since calling a listener may remove it. 168 for( std::list< Listener >::const_iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it ) 169 if( it->m_bInteractionRequested ) 170 aListeners.push_back( *it ); 171 172 m_bInteractionGranted = bInteractionGranted; 173 174 // answer the session manager even if no listeners available anymore 175 DBG_ASSERT( ! aListeners.empty(), "interactionGranted but no listeners !" ); 176 if( aListeners.empty() ) 177 { 178 if( m_pSession ) 179 m_pSession->interactionDone(); 180 return; 181 } 182 } 183 184 sal_uLong nAcquireCount = Application::ReleaseSolarMutex(); 185 for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it ) 186 it->m_xListener->approveInteraction( bInteractionGranted ); 187 188 Application::AcquireSolarMutex( nAcquireCount ); 189 } 190 191 void VCLSession::callShutdownCancelled() 192 { 193 std::list< Listener > aListeners; 194 { 195 osl::MutexGuard aGuard( m_aMutex ); 196 // copy listener list since calling a listener may remove it. 197 aListeners = m_aListeners; 198 // set back interaction state 199 m_bInteractionRequested = m_bInteractionDone = m_bInteractionGranted = false; 200 } 201 202 sal_uLong nAcquireCount = Application::ReleaseSolarMutex(); 203 for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it ) 204 it->m_xListener->shutdownCanceled(); 205 Application::AcquireSolarMutex( nAcquireCount ); 206 } 207 208 void VCLSession::callQuit() 209 { 210 std::list< Listener > aListeners; 211 { 212 osl::MutexGuard aGuard( m_aMutex ); 213 // copy listener list since calling a listener may remove it. 214 aListeners = m_aListeners; 215 // set back interaction state 216 m_bInteractionRequested = m_bInteractionDone = m_bInteractionGranted = false; 217 } 218 219 sal_uLong nAcquireCount = Application::ReleaseSolarMutex(); 220 for( std::list< Listener >::const_iterator it = aListeners.begin(); it != aListeners.end(); ++it ) 221 { 222 css::uno::Reference< XSessionManagerListener2 > xListener2( it->m_xListener, UNO_QUERY ); 223 if( xListener2.is() ) 224 xListener2->doQuit(); 225 } 226 Application::AcquireSolarMutex( nAcquireCount ); 227 } 228 229 void VCLSession::SalSessionEventProc( SalSessionEvent* pEvent ) 230 { 231 switch( pEvent->m_eType ) 232 { 233 case Interaction: 234 { 235 SalSessionInteractionEvent* pIEv = static_cast<SalSessionInteractionEvent*>(pEvent); 236 pOneInstance->callInteractionGranted( pIEv->m_bInteractionGranted ); 237 } 238 break; 239 case SaveRequest: 240 { 241 SalSessionSaveRequestEvent* pSEv = static_cast<SalSessionSaveRequestEvent*>(pEvent); 242 pOneInstance->callSaveRequested( pSEv->m_bShutdown, pSEv->m_bCancelable ); 243 } 244 break; 245 case ShutdownCancel: 246 pOneInstance->callShutdownCancelled(); 247 break; 248 case Quit: 249 pOneInstance->callQuit(); 250 break; 251 } 252 } 253 254 void SAL_CALL VCLSession::addSessionManagerListener( const css::uno::Reference<XSessionManagerListener>& xListener ) throw( RuntimeException ) 255 { 256 osl::MutexGuard aGuard( m_aMutex ); 257 258 m_aListeners.push_back( Listener( xListener ) ); 259 } 260 261 void SAL_CALL VCLSession::removeSessionManagerListener( const css::uno::Reference<XSessionManagerListener>& xListener ) throw( RuntimeException ) 262 { 263 osl::MutexGuard aGuard( m_aMutex ); 264 265 std::list< Listener >::iterator it = m_aListeners.begin(); 266 while( it != m_aListeners.end() ) 267 { 268 if( it->m_xListener == xListener ) 269 { 270 m_aListeners.erase( it ); 271 it = m_aListeners.begin(); 272 } 273 else 274 ++it; 275 } 276 } 277 278 void SAL_CALL VCLSession::queryInteraction( const css::uno::Reference<XSessionManagerListener>& xListener ) throw( RuntimeException ) 279 { 280 if( m_bInteractionGranted ) 281 { 282 if( m_bInteractionDone ) 283 xListener->approveInteraction( false ); 284 else 285 xListener->approveInteraction( true ); 286 return; 287 } 288 289 osl::MutexGuard aGuard( m_aMutex ); 290 if( ! m_bInteractionRequested ) 291 { 292 m_pSession->queryInteraction(); 293 m_bInteractionRequested = true; 294 } 295 for( std::list< Listener >::iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it ) 296 { 297 if( it->m_xListener == xListener ) 298 { 299 it->m_bInteractionRequested = true; 300 it->m_bInteractionDone = false; 301 } 302 } 303 } 304 305 void SAL_CALL VCLSession::interactionDone( const css::uno::Reference< XSessionManagerListener >& xListener ) throw( RuntimeException ) 306 { 307 osl::MutexGuard aGuard( m_aMutex ); 308 int nRequested = 0, nDone = 0; 309 for( std::list< Listener >::iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it ) 310 { 311 if( it->m_bInteractionRequested ) 312 { 313 nRequested++; 314 if( xListener == it->m_xListener ) 315 it->m_bInteractionDone = true; 316 } 317 if( it->m_bInteractionDone ) 318 nDone++; 319 } 320 if( nDone == nRequested && nDone > 0 ) 321 { 322 m_bInteractionDone = true; 323 if( m_pSession ) 324 m_pSession->interactionDone(); 325 } 326 } 327 328 void SAL_CALL VCLSession::saveDone( const css::uno::Reference< XSessionManagerListener >& xListener ) throw( RuntimeException ) 329 { 330 osl::MutexGuard aGuard( m_aMutex ); 331 332 bool bSaveDone = true; 333 for( std::list< Listener >::iterator it = m_aListeners.begin(); 334 it != m_aListeners.end(); ++it ) 335 { 336 if( it->m_xListener == xListener ) 337 it->m_bSaveDone = true; 338 if( ! it->m_bSaveDone ) 339 bSaveDone = false; 340 } 341 if( bSaveDone ) 342 { 343 m_bSaveDone = true; 344 if( m_pSession ) 345 m_pSession->saveDone(); 346 } 347 } 348 349 sal_Bool SAL_CALL VCLSession::cancelShutdown() throw( RuntimeException ) 350 { 351 return m_pSession ? (sal_Bool)m_pSession->cancelShutdown() : sal_False; 352 } 353 354 // service implementation 355 356 OUString SAL_CALL vcl_session_getImplementationName() 357 { 358 static OUString aImplementationName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.VCLSessionManagerClient" ) ); 359 return aImplementationName; 360 } 361 362 Sequence< rtl::OUString > SAL_CALL vcl_session_getSupportedServiceNames() 363 { 364 Sequence< OUString > aRet(1); 365 aRet[0] = OUString::createFromAscii("com.sun.star.frame.SessionManagerClient"); 366 return aRet; 367 } 368 369 css::uno::Reference< XInterface > SAL_CALL vcl_session_createInstance( const css::uno::Reference< XMultiServiceFactory > & /*xMultiServiceFactory*/ ) 370 { 371 ImplSVData* pSVData = ImplGetSVData(); 372 if( ! pSVData->xSMClient.is() ) 373 pSVData->xSMClient = new VCLSession(); 374 375 return css::uno::Reference< XInterface >(pSVData->xSMClient, UNO_QUERY ); 376 } 377