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