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