Updated all code to new format
[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
21 // INTERNAL INCLUDES
22 #include <dali/devel-api/common/owner-container.h>
23 #include <dali/devel-api/threading/mutex.h>
24 #include <dali/internal/common/message.h>
25 #include <dali/internal/event/common/complete-notification-interface.h>
26 #include <dali/internal/event/common/property-notification-impl.h>
27 #include <dali/public-api/common/dali-common.h>
28
29 namespace Dali
30 {
31 namespace Internal
32 {
33 namespace
34 {
35 typedef Dali::Vector<CompleteNotificationInterface*> InterfaceContainer;
36
37 /**
38  * helper to move elements from one container to another
39  * @param from where to move
40  * @param to move target
41  */
42 void MoveElements(InterfaceContainer& from, InterfaceContainer& to)
43 {
44   // check if there's something in from
45   const InterfaceContainer::SizeType fromCount = from.Count();
46   if(fromCount > 0u)
47   {
48     // check if to has some elements
49     const InterfaceContainer::SizeType toCount = to.Count();
50     if(toCount == 0u)
51     {
52       // to is empty so we can swap with from
53       to.Swap(from);
54     }
55     else
56     {
57       to.Reserve(toCount + fromCount);
58       for(InterfaceContainer::SizeType i = 0; i < fromCount; ++i)
59       {
60         to.PushBack(from[i]);
61       }
62       from.Clear();
63     }
64   }
65 }
66 } // namespace
67
68 using MessageQueueMutex = Dali::Mutex;
69 using MessageContainer  = OwnerContainer<MessageBase*>;
70
71 struct NotificationManager::Impl
72 {
73   Impl()
74   {
75     // reserve space on the vectors to avoid reallocs
76     // applications typically have up-to 20-30 notifications at startup
77     updateCompletedMessageQueue.Reserve(32);
78     updateWorkingMessageQueue.Reserve(32);
79     eventMessageQueue.Reserve(32);
80
81     // only a few manager objects get complete notifications (animation, render list, property notifications, ...)
82     updateCompletedInterfaceQueue.Reserve(4);
83     updateWorkingInterfaceQueue.Reserve(4);
84     eventInterfaceQueue.Reserve(4);
85   }
86
87   ~Impl() = default;
88
89   // queueMutex must be locked whilst accessing queue
90   MessageQueueMutex queueMutex;
91   // three queues for objects owned by notification manager
92   MessageContainer updateCompletedMessageQueue;
93   MessageContainer updateWorkingMessageQueue;
94   MessageContainer eventMessageQueue;
95   // three queues for objects referenced by notification manager
96   InterfaceContainer updateCompletedInterfaceQueue;
97   InterfaceContainer updateWorkingInterfaceQueue;
98   InterfaceContainer eventInterfaceQueue;
99 };
100
101 NotificationManager::NotificationManager()
102 {
103   mImpl = new Impl();
104 }
105
106 NotificationManager::~NotificationManager()
107 {
108   delete mImpl;
109 }
110
111 void NotificationManager::QueueCompleteNotification(CompleteNotificationInterface* instance)
112 {
113   // queueMutex must be locked whilst accessing queues
114   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
115
116   mImpl->updateWorkingInterfaceQueue.PushBack(instance);
117 }
118
119 void NotificationManager::QueueMessage(MessageBase* message)
120 {
121   DALI_ASSERT_DEBUG(NULL != message);
122
123   // queueMutex must be locked whilst accessing queues
124   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
125
126   mImpl->updateWorkingMessageQueue.PushBack(message);
127 }
128
129 void NotificationManager::UpdateCompleted()
130 {
131   // queueMutex must be locked whilst accessing queues
132   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
133   // Move messages from update working queue to completed queue
134   // note that in theory its possible for update completed to have last frames
135   // events as well still hanging around. we need to keep them as well
136   mImpl->updateCompletedMessageQueue.MoveFrom(mImpl->updateWorkingMessageQueue);
137   // move pointers from interface queue
138   MoveElements(mImpl->updateWorkingInterfaceQueue, mImpl->updateCompletedInterfaceQueue);
139   // finally the lock is released
140 }
141
142 bool NotificationManager::MessagesToProcess()
143 {
144   // queueMutex must be locked whilst accessing queues
145   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
146
147   return (0u < mImpl->updateCompletedMessageQueue.Count() ||
148           (0u < mImpl->updateCompletedInterfaceQueue.Count()));
149 }
150
151 void NotificationManager::ProcessMessages()
152 {
153   // queueMutex must be locked whilst accessing queues
154   {
155     MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
156
157     // Move messages from update completed queue to event queue
158     // note that in theory its possible for event queue to have
159     // last frames events as well still hanging around so need to keep them
160     mImpl->eventMessageQueue.MoveFrom(mImpl->updateCompletedMessageQueue);
161     MoveElements(mImpl->updateCompletedInterfaceQueue, mImpl->eventInterfaceQueue);
162   }
163   // end of scope, lock is released
164
165   MessageContainer::Iterator       iter = mImpl->eventMessageQueue.Begin();
166   const MessageContainer::Iterator end  = mImpl->eventMessageQueue.End();
167   for(; iter != end; ++iter)
168   {
169     (*iter)->Process(0u /*ignored*/);
170   }
171   // release the processed messages from event side queue
172   mImpl->eventMessageQueue.Clear();
173
174   InterfaceContainer::Iterator       iter2 = mImpl->eventInterfaceQueue.Begin();
175   const InterfaceContainer::Iterator end2  = mImpl->eventInterfaceQueue.End();
176   for(; iter2 != end2; ++iter2)
177   {
178     CompleteNotificationInterface* interface = *iter2;
179     if(interface)
180     {
181       interface->NotifyCompleted();
182     }
183   }
184   // just clear the container, we dont own the objects
185   mImpl->eventInterfaceQueue.Clear();
186 }
187
188 } // namespace Internal
189
190 } // namespace Dali