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_unotools.hxx"
30 #include <unotools/desktopterminationobserver.hxx>
31 
32 /** === begin UNO includes === **/
33 #include <com/sun/star/frame/XTerminateListener.hpp>
34 #include <com/sun/star/frame/XDesktop.hpp>
35 /** === end UNO includes === **/
36 #include <cppuhelper/implbase1.hxx>
37 #include <comphelper/processfactory.hxx>
38 
39 #include <list>
40 
41 //........................................................................
42 namespace utl
43 {
44 //........................................................................
45 
46     using namespace ::com::sun::star::uno;
47     using namespace ::com::sun::star::lang;
48     using namespace ::com::sun::star::frame;
49 
50     namespace
51     {
52         //................................................................
53         typedef ::std::list< ITerminationListener* > Listeners;
54 
55         struct ListenerAdminData
56         {
57             Listeners   aListeners;
58             bool        bAlreadyTerminated;
59             bool        bCreatedAdapter;
60 
61             ListenerAdminData() : bAlreadyTerminated( false ), bCreatedAdapter( false ) { }
62         };
63 
64         //................................................................
65         ListenerAdminData& getListenerAdminData()
66         {
67             static ListenerAdminData s_aData;
68             return s_aData;
69         }
70 
71         //================================================================
72 	    //= OObserverImpl
73 	    //================================================================
74         class OObserverImpl : public ::cppu::WeakImplHelper1< XTerminateListener >
75         {
76         public:
77             static void ensureObservation();
78 
79         protected:
80             OObserverImpl();
81             ~OObserverImpl();
82 
83         private:
84             // XTerminateListener
85             virtual void SAL_CALL queryTermination( const EventObject& Event ) throw (TerminationVetoException, RuntimeException);
86             virtual void SAL_CALL notifyTermination( const EventObject& Event ) throw (RuntimeException);
87 
88             // XEventListener
89             virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
90         };
91 
92         //--------------------------------------------------------------------
93         OObserverImpl::OObserverImpl()
94         {
95         }
96 
97         //--------------------------------------------------------------------
98         OObserverImpl::~OObserverImpl()
99         {
100         }
101 
102         //--------------------------------------------------------------------
103         void OObserverImpl::ensureObservation()
104         {
105             {
106                 if ( getListenerAdminData().bCreatedAdapter )
107                     return;
108                 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
109                 if ( getListenerAdminData().bCreatedAdapter )
110                     return;
111 
112                 getListenerAdminData().bCreatedAdapter = true;
113             }
114 
115             try
116             {
117                 Reference< XDesktop > xDesktop;
118                 xDesktop = xDesktop.query( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ) ) );
119                 OSL_ENSURE( xDesktop.is(), "OObserverImpl::ensureObservation: could not ensureObservation the desktop!" );
120                 if ( xDesktop.is() )
121                     xDesktop->addTerminateListener( new OObserverImpl );
122             }
123             catch( const Exception& )
124             {
125             	OSL_ENSURE( sal_False, "OObserverImpl::ensureObservation: caught an exception!" );
126             }
127         }
128 
129         //--------------------------------------------------------------------
130         void SAL_CALL OObserverImpl::queryTermination( const EventObject& /*Event*/ ) throw (TerminationVetoException, RuntimeException)
131         {
132             Listeners aToNotify;
133             {
134                 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
135                 aToNotify = getListenerAdminData().aListeners;
136             }
137 
138             for ( Listeners::const_iterator listener = aToNotify.begin();
139                   listener != aToNotify.end();
140                   ++listener
141                 )
142             {
143                 if ( !(*listener)->queryTermination() )
144                     throw TerminationVetoException();
145             }
146         }
147 
148         //--------------------------------------------------------------------
149         void SAL_CALL OObserverImpl::notifyTermination( const EventObject& /*Event*/ ) throw (RuntimeException)
150         {
151             // get the listeners
152             Listeners aToNotify;
153             {
154                 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
155                 OSL_ENSURE( !getListenerAdminData().bAlreadyTerminated, "OObserverImpl::notifyTermination: terminated twice?" );
156                 aToNotify = getListenerAdminData().aListeners;
157                 getListenerAdminData().bAlreadyTerminated = true;
158             }
159 
160             // notify the listeners
161             for ( Listeners::const_iterator listener = aToNotify.begin();
162                   listener != aToNotify.end();
163                   ++listener
164                 )
165             {
166                 (*listener)->notifyTermination();
167             }
168 
169             // clear the listener container
170             {
171                 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
172                 getListenerAdminData().aListeners.clear();
173             }
174         }
175 
176         //--------------------------------------------------------------------
177         void SAL_CALL OObserverImpl::disposing( const EventObject& /*Event*/ ) throw (RuntimeException)
178         {
179 #if OSL_DEBUG_LEVEL > 0
180             ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
181             OSL_ENSURE( getListenerAdminData().bAlreadyTerminated, "OObserverImpl::disposing: disposing without terminated?" );
182 #endif
183             // not interested in
184         }
185     }
186 
187 	//====================================================================
188 	//= DesktopTerminationObserver
189 	//====================================================================
190 	//--------------------------------------------------------------------
191     void DesktopTerminationObserver::registerTerminationListener( ITerminationListener* _pListener )
192     {
193         if ( !_pListener )
194             return;
195 
196         {
197             ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
198             if ( getListenerAdminData().bAlreadyTerminated )
199             {
200                 _pListener->notifyTermination();
201                 return;
202             }
203 
204             getListenerAdminData().aListeners.push_back( _pListener );
205         }
206 
207         OObserverImpl::ensureObservation();
208     }
209 
210 	//--------------------------------------------------------------------
211     void DesktopTerminationObserver::revokeTerminationListener( ITerminationListener* _pListener )
212     {
213         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
214         Listeners& rListeners = getListenerAdminData().aListeners;
215         for ( Listeners::iterator lookup = rListeners.begin();
216               lookup != rListeners.end();
217               ++lookup
218               )
219         {
220             if ( *lookup == _pListener )
221             {
222                 rListeners.erase( lookup );
223                 break;
224             }
225         }
226     }
227 
228 //........................................................................
229 } // namespace utl
230 //........................................................................
231 
232