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