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