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