Guarantee notifications are served in the right order in the case that event thread...
[platform/core/uifw/dali-core.git] / dali / internal / event / common / notification-manager.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/common/notification-manager.h>
20 #include <dali/internal/common/owner-container.h>
21 #include <dali/internal/common/message.h>
22
23 // EXTERNAL INCLUDES
24 #ifdef __clang__
25 #pragma clang diagnostic push
26 #pragma clang diagnostic ignored "-Wall"
27
28 #include <boost/thread/mutex.hpp>
29
30 #pragma clang diagnostic pop
31 #else
32
33 #include <boost/thread/mutex.hpp>
34
35 #endif // __clang__
36
37 // INTERNAL INCLUDES
38 #include <dali/public-api/common/dali-common.h>
39 #include <dali/internal/event/common/property-notification-impl.h>
40
41 namespace Dali
42 {
43
44 namespace Internal
45 {
46
47 typedef boost::mutex MessageQueueMutex;
48 typedef OwnerContainer< MessageBase* > MessageContainer;
49
50 struct NotificationManager::Impl
51 {
52   Impl()
53   : notificationCount(0)
54   {
55     // reserve space on the vectors to avoid reallocs
56     // applications typically have upto 20-30 notifications at startup
57     updateCompletedQueue.Reserve( 32 );
58     updateWorkingQueue.Reserve( 32 );
59     eventQueue.Reserve( 32 );
60   }
61
62   ~Impl()
63   {
64   }
65
66   // Used to skip duplicate operations during Notify()
67   unsigned int notificationCount;
68
69   // queueMutex must be locked whilst accessing queue
70   MessageQueueMutex queueMutex;
71   MessageContainer updateCompletedQueue;
72   MessageContainer updateWorkingQueue;
73   MessageContainer eventQueue;
74 };
75
76 NotificationManager::NotificationManager()
77 {
78   mImpl = new Impl();
79 }
80
81 NotificationManager::~NotificationManager()
82 {
83   delete mImpl;
84 }
85
86 void NotificationManager::QueueMessage( MessageBase* message )
87 {
88   DALI_ASSERT_DEBUG( NULL != message );
89
90   // queueMutex must be locked whilst accessing queues
91   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
92
93   mImpl->updateWorkingQueue.PushBack( message );
94 }
95
96 void NotificationManager::UpdateCompleted()
97 {
98   // queueMutex must be locked whilst accessing queues
99   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
100   // Move messages from update working queue to completed queue
101   // note that in theory its possible for update completed to have last frames
102   // events as well still hanging around. we need to keep them as well
103   mImpl->updateCompletedQueue.MoveFrom( mImpl->updateWorkingQueue );
104   // finally the lock is released
105 }
106
107 bool NotificationManager::MessagesToProcess()
108 {
109   // queueMutex must be locked whilst accessing queues
110   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
111
112   return ( false == mImpl->updateCompletedQueue.IsEmpty() );
113 }
114
115 void NotificationManager::ProcessMessages()
116 {
117   // Done before messages are processed, for notification count comparisons
118   ++mImpl->notificationCount;
119
120   // queueMutex must be locked whilst accessing queues
121   {
122     MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
123
124     // Move messages from update completed queue to event queue
125     // note that in theory its possible for event queue to have
126     // last frames events as well still hanging around so need to keep them
127     mImpl->eventQueue.MoveFrom( mImpl->updateCompletedQueue );
128   }
129   // end of scope, lock is released
130
131   MessageContainer::Iterator iter = mImpl->eventQueue.Begin();
132   MessageContainer::Iterator end = mImpl->eventQueue.End();
133   for( ; iter != end; ++iter )
134   {
135     (*iter)->Process( 0u/*ignored*/ );
136   }
137
138   // release the processed messages from event side queue
139   mImpl->eventQueue.Clear();
140 }
141
142 unsigned int NotificationManager::GetNotificationCount() const
143 {
144   return mImpl->notificationCount;
145 }
146
147 } // namespace Internal
148
149 } // namespace Dali