Salome HOME
Update copyrights 2014.
[modules/gui.git] / src / Event / SALOME_Event.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  KERNEL SALOME_Event : Define event posting mechanism
24 //  File   : SALOME_Event.cxx
25 //  Author : Sergey ANIKIN
26 //
27 #include "SALOME_Event.h"
28
29 #include <QSemaphore>
30 #include <QApplication>
31
32 // asv 21.02.05 : introducing multi-platform approach of thread comparison
33 // - on Unix using pthread_t type for storing ThreadId
34 // - on Win32 using integer type for storing ThreadId
35 // NOT using integer ThreadId on both Unix and Win32 because (from documentation):
36 // "...Do not allow your program to rely on the internal structure or size of the pthread_t..."
37
38 #ifdef WIN32
39 #include <windows.h>
40 static DWORD myThread;
41 #else
42 #include <pthread.h>
43 static pthread_t myThread;
44 #endif
45
46 /*!
47   \class InitEvent
48   \brief Helper event class responsible for initializing SALOME_Event
49   mechanism by the main thread ID
50  */
51 class InitEvent : public SALOME_Event
52 {
53 public:
54   InitEvent();
55   virtual      ~InitEvent();
56   virtual void Execute();
57 };
58
59 /*!
60   \brief Constructor, initializes the event mechanism by the current thread ID.
61   It is asssumed to be the main thread ID, so be careful!
62 */
63 InitEvent::InitEvent()
64 {
65   GetSessionThread();
66 }
67
68 /*!
69   \brief Destructor, does nothing.
70 */
71 InitEvent::~InitEvent()
72 {
73 }
74
75 /*!
76   \brief Nothing to be executed for this kind of event.
77 */
78 void InitEvent::Execute()
79 {
80 }
81
82 // NOTE: Here the SALOME event mechanism is initalized by the 
83 // current thread ID that is always assumed to be the main thread ID.
84 // This should be revised as soon as the application library is no longer
85 // linked against the Event library (i.e. this static object is not created or created 
86 // outside the main thread).
87 static InitEvent myInitEvent;
88
89 /*!
90   \class SALOME_CustomEvent
91   \brief Generic event class for user-defined events
92   
93   This class contains a generic void* data member that may be used
94   for transferring event-specific data to the receiver.
95
96   \warning The internal data is not destroyed by the class destructor.
97 */
98
99 /*!
100   \brief Constructor.
101   \param type event type
102 */
103 SALOME_CustomEvent::SALOME_CustomEvent( int type )
104 : QEvent( (QEvent::Type)type ), d( 0 )
105 {
106 }
107
108 /*!
109   \brief Constructor.
110   \param type event type
111   \param data custom data
112 */
113 SALOME_CustomEvent::SALOME_CustomEvent( QEvent::Type type, void* data )
114 : QEvent( type ), d( data )
115 {
116 }
117
118 /*!
119   \brief Get custom data.
120   \return pointer to the internal data
121 */
122 void* SALOME_CustomEvent::data() const
123 {
124   return d;
125 }
126
127 /*!
128   \brief Set custom data.
129   \param data pointer to the internal data
130 */
131 void SALOME_CustomEvent::setData( void* data )
132 {
133   d = data;
134 }
135
136 /*!
137   \class SALOME_Event
138   \brief The class which encapsulates data and functionality required for 
139          posting component-specific events to perform arbitrary operations 
140          in the main GUI thread. 
141
142   SALOME_Event objects can be posted by any thread belonging to the GUI process.
143   
144   It is necessary to derive a custom event class from SALOME_Event and 
145   re-implement virtual Execute() method. This method should actually perform 
146   the desirable operation. To pass all the required data to Execute() and 
147   store a return value, arbitrary data fields can be added to the custom 
148   event class. There is no need to protect such fields with a mutex, for only
149   one thread working with a SALOME_Event object is active at any moment.
150   
151   Usage:
152   - Create SALOME_Event. Components can derive their own event class from 
153   SALOME_Event in order to pass custom data to the event handler.
154   - Call process() method to post the event. After process() execution
155   it is possible to examine fields of your custom event object.
156   - Perform delete operator on the event to wake up the desktop (you can also 
157   set <autoRelease>  parameter to \c true to automatically wake up desktop after 
158   process().
159   
160   The method processed() is used by the desktop to signal that event processing 
161   has been completed.
162
163   To make all this work, it is necessary to call static method GetSessionThread()
164   during the application initialization, i.e. from main() function.
165   It is important to call this method from the primary application thread.
166
167   Caveats: 
168   - there are no.
169 */
170
171 //! Total number of semaphore resources
172 const int NumberOfResources = 2;
173
174 /*!
175   \brief Initialize event mechanism.
176
177   This function sets up the main application thread. It should be called
178   during the application initialization, i.e. main() function.
179 */
180 void SALOME_Event::GetSessionThread(){
181 #ifdef WIN32
182   myThread = ::GetCurrentThreadId();
183 #else
184   myThread = pthread_self();
185 #endif
186 }
187
188 /*!
189   \brief Check if the processing is in the main application thread.
190   \return \c true if this method is called from the main application thread
191 */
192 bool SALOME_Event::IsSessionThread(){
193   bool aResult = false;
194 #ifdef WIN32
195   aResult = myThread == ::GetCurrentThreadId();
196 #else
197   aResult = myThread == pthread_self();
198 #endif
199   return aResult;
200 }
201
202 /*!
203   \brief Constructor.
204 */
205 SALOME_Event::SALOME_Event(){
206   // Prepare the semaphore 
207   mySemaphore = new QSemaphore( NumberOfResources );
208   mySemaphore->acquire( NumberOfResources );
209 }
210
211 /*!
212   \brief Destructor.
213 */
214 SALOME_Event::~SALOME_Event(){
215   if ( mySemaphore->available() < NumberOfResources )
216     mySemaphore->release( NumberOfResources - mySemaphore->available() );
217   delete mySemaphore;
218 }
219
220 /*!
221   \brief This method should be called by the main GUI thread
222   in order to execute the code specific for this event and finally
223   to inform the calling thread that the event 
224   has been processed waking it up with help of the semaphore .
225  */
226 void SALOME_Event::ExecutePostedEvent()
227 {
228   // Diagnose incorrect usage of SALOME_Event API
229   if ( !IsSessionThread() ){
230     qWarning( "SALOME_Event::ExecutePostedEvent() is called from a secondary thread that might mean an error in application logic!" );
231   }
232   // Actual execution specific for particular kind of event
233   Execute();
234   // Signal the calling thread that the event has been processed
235   processed();
236 }
237
238 /*!
239   \brief Post the event and wait for its completion.
240   process() should be called from a secondary thread only. 
241   \sa processed()
242 */
243 void SALOME_Event::process()
244 {
245   // Diagnose incorrect usage of SALOME_Event API
246   if ( IsSessionThread() ){
247     qWarning( "SALOME_Event::process() is called from the main GUI thread that might mean an error in application logic!" );
248   }
249
250   QApplication::postEvent( qApp, new SALOME_CustomEvent( SALOME_EVENT, (void*)this ) );
251   mySemaphore->acquire( 1 );
252 }
253
254 /*!
255   \brief Use this method to signal that this event has been processed.
256 */
257 void SALOME_Event::processed()
258 {
259   mySemaphore->release( 1 );
260 }
261
262 /*!
263   \fn virtual void SALOME_Event::Execute();
264   \brief This method should be redefined in the successor classes
265          to do real work.
266 */
267   
268 /*!
269   \class TMemFunEvent
270   \brief Template class for event which calls the function
271   without arguments and returning result.
272 */
273
274 /*!
275   \class TVoidMemFunEvent
276   \brief Template class for event which calls the function
277   without arguments and without return value.
278 */
279
280 /*!
281   \class TMemFun1ArgEvent
282   \brief Template class for event which calls the function
283   with one argument and returning result.
284 */
285
286 /*!
287   \class TVoidMemFun1ArgEvent
288   \brief Template class for event which calls the function
289   with one argument and without return value.
290 */
291
292 /*!
293   \class TMemFun2ArgEvent
294   \brief Template class for event which calls the function
295   with two arguments and returning result.
296 */
297
298 /*!
299   \class TVoidMemFun2ArgEvent
300   \brief Template class for event which calls the function
301   with two arguments and without return value.
302 */
303
304 /*!
305   \fn ProcessEvent
306   \brief Template function for processing events with return value.
307 */
308
309 /*!
310   \fn ProcessVoidEvent
311   \brief Template function for processing events without return value.
312 */