Merge "Repeat ProcessEvents idler if requested." into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / adaptor-impl.cpp
1 /*
2  * Copyright (c) 2023 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/adaptor/common/adaptor-builder-impl.h>
20 #include <dali/internal/adaptor/common/adaptor-impl.h>
21 #include <dali/internal/addons/common/addon-manager-factory.h>
22 #include <dali/internal/addons/common/addon-manager-impl.h>
23
24 // EXTERNAL INCLUDES
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali/devel-api/common/stage.h>
27 #include <dali/integration-api/addon-manager.h>
28 #include <dali/integration-api/context-notifier.h>
29 #include <dali/integration-api/core.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/integration-api/events/key-event-integ.h>
32 #include <dali/integration-api/events/touch-event-integ.h>
33 #include <dali/integration-api/events/wheel-event-integ.h>
34 #include <dali/integration-api/input-options.h>
35 #include <dali/integration-api/processor-interface.h>
36 #include <dali/integration-api/profiling.h>
37 #include <dali/integration-api/trace.h>
38 #include <dali/public-api/actors/layer.h>
39 #include <dali/public-api/events/wheel-event.h>
40 #include <dali/public-api/object/any.h>
41 #include <dali/public-api/object/object-registry.h>
42 #include <errno.h>
43 #include <sys/stat.h>
44
45 // INTERNAL INCLUDES
46 #include <dali/internal/adaptor/common/lifecycle-observer.h>
47 #include <dali/internal/adaptor/common/thread-controller-interface.h>
48 #include <dali/internal/system/common/performance-interface-factory.h>
49 #include <dali/internal/system/common/thread-controller.h>
50 #include <dali/public-api/dali-adaptor-common.h>
51
52 #include <dali/internal/graphics/gles/egl-graphics-factory.h>
53 #include <dali/internal/graphics/gles/egl-graphics.h> // Temporary until Core is abstracted
54
55 #include <dali/devel-api/text-abstraction/font-client.h>
56
57 #include <dali/internal/accessibility/common/tts-player-impl.h>
58 #include <dali/internal/text-clipboard/common/text-clipboard-impl.h>
59 #include <dali/internal/graphics/common/egl-image-extensions.h>
60 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
61 #include <dali/internal/graphics/gles/gl-implementation.h>
62 #include <dali/internal/graphics/gles/gl-proxy-implementation.h>
63 #include <dali/internal/system/common/callback-manager.h>
64 #include <dali/internal/system/common/object-profiler.h>
65 #include <dali/internal/system/common/system-factory.h>
66 #include <dali/internal/window-system/common/display-connection.h>
67 #include <dali/internal/window-system/common/display-utils.h> // For Utils::MakeUnique
68 #include <dali/internal/window-system/common/event-handler.h>
69 #include <dali/internal/window-system/common/window-impl.h>
70 #include <dali/internal/window-system/common/window-render-surface.h>
71 #include <dali/internal/window-system/common/window-system.h>
72
73 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
74 #include <dali/internal/system/common/logging.h>
75
76 #include <dali/internal/imaging/common/image-loader-plugin-proxy.h>
77 #include <dali/internal/imaging/common/image-loader.h>
78 #include <dali/internal/system/common/locale-utils.h>
79
80 #include <dali/devel-api/adaptor-framework/environment-variable.h>
81 #include <dali/internal/system/common/configuration-manager.h>
82 #include <dali/internal/system/common/environment-variables.h>
83
84 using Dali::TextAbstraction::FontClient;
85
86 extern std::string GetSystemCachePath();
87
88 namespace Dali
89 {
90 namespace Internal
91 {
92 namespace Adaptor
93 {
94 namespace
95 {
96 thread_local Adaptor* gThreadLocalAdaptor = NULL; // raw thread specific pointer to allow Adaptor::Get
97
98 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
99
100 const char* ENABLE_IMAGE_LOADER_PLUGIN_ENV = "DALI_ENABLE_IMAGE_LOADER_PLUGIN";
101 } // unnamed namespace
102
103 Dali::Adaptor* Adaptor::New(Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface* surface, EnvironmentOptions* environmentOptions, ThreadMode threadMode)
104 {
105   Dali::Adaptor* adaptor = new Dali::Adaptor;
106   Adaptor*       impl    = new Adaptor(window, *adaptor, surface, environmentOptions, threadMode);
107   adaptor->mImpl         = impl;
108
109   Dali::Internal::Adaptor::AdaptorBuilder* mAdaptorBuilder = new AdaptorBuilder(*(impl->mEnvironmentOptions));
110   auto                                     graphicsFactory = mAdaptorBuilder->GetGraphicsFactory();
111
112   impl->Initialize(graphicsFactory);
113   delete mAdaptorBuilder; // Not needed anymore as the graphics interface has now been created
114
115   return adaptor;
116 }
117
118 Dali::Adaptor* Adaptor::New(Dali::Integration::SceneHolder window, EnvironmentOptions* environmentOptions)
119 {
120   Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation(window);
121   Dali::Adaptor*                  adaptor    = New(window, windowImpl.GetSurface(), environmentOptions, ThreadMode::NORMAL);
122   windowImpl.SetAdaptor(*adaptor);
123   return adaptor;
124 }
125
126 Dali::Adaptor* Adaptor::New(GraphicsFactory& graphicsFactory, Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface* surface, EnvironmentOptions* environmentOptions, ThreadMode threadMode)
127 {
128   Dali::Adaptor* adaptor = new Dali::Adaptor;                                                      // Public adaptor
129   Adaptor*       impl    = new Adaptor(window, *adaptor, surface, environmentOptions, threadMode); // Impl adaptor
130   adaptor->mImpl         = impl;
131
132   impl->Initialize(graphicsFactory);
133
134   return adaptor;
135 } // Called second
136
137 Dali::Adaptor* Adaptor::New(GraphicsFactory& graphicsFactory, Dali::Integration::SceneHolder window, EnvironmentOptions* environmentOptions)
138 {
139   Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation(window);
140   Dali::Adaptor*                  adaptor    = New(graphicsFactory, window, windowImpl.GetSurface(), environmentOptions, ThreadMode::NORMAL);
141   windowImpl.SetAdaptor(*adaptor);
142   return adaptor;
143 } // Called first
144
145 void Adaptor::Initialize(GraphicsFactory& graphicsFactory)
146 {
147   // all threads here (event, update, and render) will send their logs to TIZEN Platform's LogMessage handler.
148   Dali::Integration::Log::LogFunction logFunction(Dali::TizenPlatform::LogMessage);
149   mEnvironmentOptions->SetLogFunction(logFunction);
150   mEnvironmentOptions->InstallLogFunction(); // install logging for main thread
151
152   mPlatformAbstraction = new TizenPlatform::TizenPlatformAbstraction;
153
154   std::string path;
155   GetDataStoragePath(path);
156   mPlatformAbstraction->SetDataStoragePath(path);
157
158   if(mEnvironmentOptions->PerformanceServerRequired())
159   {
160     mPerformanceInterface = PerformanceInterfaceFactory::CreateInterface(*this, *mEnvironmentOptions);
161   }
162
163   mEnvironmentOptions->CreateTraceManager(mPerformanceInterface);
164   mEnvironmentOptions->InstallTraceFunction(); // install tracing for main thread
165
166   mCallbackManager = Dali::Internal::Adaptor::GetSystemFactory()->CreateCallbackManager();
167
168   Dali::Internal::Adaptor::SceneHolder* defaultWindow = mWindows.front();
169
170   DALI_ASSERT_DEBUG(defaultWindow->GetSurface() && "Surface not initialized");
171
172   mGraphics = std::unique_ptr<GraphicsInterface>(&graphicsFactory.Create());
173
174   // Create the AddOnManager
175   mAddOnManager.reset(Dali::Internal::AddOnManagerFactory::CreateAddOnManager());
176
177   mCore = Integration::Core::New(*this,
178                                  *mPlatformAbstraction,
179                                  mGraphics->GetController(),
180                                  (0u != mEnvironmentOptions->GetRenderToFboInterval()) ? Integration::RenderToFrameBuffer::TRUE : Integration::RenderToFrameBuffer::FALSE,
181                                  mGraphics->GetDepthBufferRequired(),
182                                  mGraphics->GetStencilBufferRequired(),
183                                  mGraphics->GetPartialUpdateRequired());
184
185   defaultWindow->SetAdaptor(Get());
186
187   Dali::Integration::SceneHolder defaultSceneHolder(defaultWindow);
188
189   mWindowCreatedSignal.Emit(defaultSceneHolder);
190
191   const unsigned int timeInterval = mEnvironmentOptions->GetObjectProfilerInterval();
192   if(0u < timeInterval)
193   {
194     mObjectProfiler = new ObjectProfiler(mCore->GetObjectRegistry(), timeInterval);
195   }
196
197   const uint32_t poolTimeInterval = mEnvironmentOptions->GetMemoryPoolInterval();
198   if(0u < poolTimeInterval)
199   {
200     mMemoryPoolTimer = Dali::Timer::New(poolTimeInterval * 1000);
201     mMemoryPoolTimer.TickSignal().Connect(mMemoryPoolTimerSlotDelegate, &Adaptor::MemoryPoolTimeout);
202     mMemoryPoolTimer.Start();
203   }
204
205   mNotificationTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &Adaptor::ProcessCoreEvents), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
206
207   mDisplayConnection = Dali::DisplayConnection::New(*mGraphics, defaultWindow->GetSurface()->GetSurfaceType());
208
209   mThreadController = new ThreadController(*this, *mEnvironmentOptions, mThreadMode);
210
211   // Should be called after Core creation
212   if(mEnvironmentOptions->GetPanGestureLoggingLevel())
213   {
214     Integration::EnableProfiling(Dali::Integration::PROFILING_TYPE_PAN_GESTURE);
215   }
216   if(mEnvironmentOptions->GetPanGesturePredictionMode() >= 0)
217   {
218     Integration::SetPanGesturePredictionMode(mEnvironmentOptions->GetPanGesturePredictionMode());
219   }
220   if(mEnvironmentOptions->GetPanGesturePredictionAmount() >= 0)
221   {
222     Integration::SetPanGesturePredictionAmount(mEnvironmentOptions->GetPanGesturePredictionAmount());
223   }
224   if(mEnvironmentOptions->GetPanGestureMaximumPredictionAmount() >= 0)
225   {
226     Integration::SetPanGestureMaximumPredictionAmount(mEnvironmentOptions->GetPanGestureMaximumPredictionAmount());
227   }
228   if(mEnvironmentOptions->GetPanGestureMinimumPredictionAmount() >= 0)
229   {
230     Integration::SetPanGestureMinimumPredictionAmount(mEnvironmentOptions->GetPanGestureMinimumPredictionAmount());
231   }
232   if(mEnvironmentOptions->GetPanGesturePredictionAmountAdjustment() >= 0)
233   {
234     Integration::SetPanGesturePredictionAmountAdjustment(mEnvironmentOptions->GetPanGesturePredictionAmountAdjustment());
235   }
236   if(mEnvironmentOptions->GetPanGestureSmoothingMode() >= 0)
237   {
238     Integration::SetPanGestureSmoothingMode(mEnvironmentOptions->GetPanGestureSmoothingMode());
239   }
240   if(mEnvironmentOptions->GetPanGestureSmoothingAmount() >= 0.0f)
241   {
242     Integration::SetPanGestureSmoothingAmount(mEnvironmentOptions->GetPanGestureSmoothingAmount());
243   }
244   if(mEnvironmentOptions->GetPanGestureUseActualTimes() >= 0)
245   {
246     Integration::SetPanGestureUseActualTimes(mEnvironmentOptions->GetPanGestureUseActualTimes() == 0 ? true : false);
247   }
248   if(mEnvironmentOptions->GetPanGestureInterpolationTimeRange() >= 0)
249   {
250     Integration::SetPanGestureInterpolationTimeRange(mEnvironmentOptions->GetPanGestureInterpolationTimeRange());
251   }
252   if(mEnvironmentOptions->GetPanGestureScalarOnlyPredictionEnabled() >= 0)
253   {
254     Integration::SetPanGestureScalarOnlyPredictionEnabled(mEnvironmentOptions->GetPanGestureScalarOnlyPredictionEnabled() == 0 ? true : false);
255   }
256   if(mEnvironmentOptions->GetPanGestureTwoPointPredictionEnabled() >= 0)
257   {
258     Integration::SetPanGestureTwoPointPredictionEnabled(mEnvironmentOptions->GetPanGestureTwoPointPredictionEnabled() == 0 ? true : false);
259   }
260   if(mEnvironmentOptions->GetPanGestureTwoPointInterpolatePastTime() >= 0)
261   {
262     Integration::SetPanGestureTwoPointInterpolatePastTime(mEnvironmentOptions->GetPanGestureTwoPointInterpolatePastTime());
263   }
264   if(mEnvironmentOptions->GetPanGestureTwoPointVelocityBias() >= 0.0f)
265   {
266     Integration::SetPanGestureTwoPointVelocityBias(mEnvironmentOptions->GetPanGestureTwoPointVelocityBias());
267   }
268   if(mEnvironmentOptions->GetPanGestureTwoPointAccelerationBias() >= 0.0f)
269   {
270     Integration::SetPanGestureTwoPointAccelerationBias(mEnvironmentOptions->GetPanGestureTwoPointAccelerationBias());
271   }
272   if(mEnvironmentOptions->GetPanGestureMultitapSmoothingRange() >= 0)
273   {
274     Integration::SetPanGestureMultitapSmoothingRange(mEnvironmentOptions->GetPanGestureMultitapSmoothingRange());
275   }
276   if(mEnvironmentOptions->GetMinimumPanDistance() >= 0)
277   {
278     Integration::SetPanGestureMinimumDistance(mEnvironmentOptions->GetMinimumPanDistance());
279   }
280   if(mEnvironmentOptions->GetMinimumPanEvents() >= 0)
281   {
282     Integration::SetPanGestureMinimumPanEvents(mEnvironmentOptions->GetMinimumPanEvents());
283   }
284   if(mEnvironmentOptions->GetMinimumPinchDistance() >= 0)
285   {
286     Integration::SetPinchGestureMinimumDistance(mEnvironmentOptions->GetMinimumPinchDistance());
287   }
288   if(mEnvironmentOptions->GetMinimumPinchTouchEvents() >= 0)
289   {
290     Integration::SetPinchGestureMinimumTouchEvents(mEnvironmentOptions->GetMinimumPinchTouchEvents());
291   }
292   if(mEnvironmentOptions->GetMinimumPinchTouchEventsAfterStart() >= 0)
293   {
294     Integration::SetPinchGestureMinimumTouchEventsAfterStart(mEnvironmentOptions->GetMinimumPinchTouchEventsAfterStart());
295   }
296   if(mEnvironmentOptions->GetMinimumRotationTouchEvents() >= 0)
297   {
298     Integration::SetRotationGestureMinimumTouchEvents(mEnvironmentOptions->GetMinimumRotationTouchEvents());
299   }
300   if(mEnvironmentOptions->GetMinimumRotationTouchEventsAfterStart() >= 0)
301   {
302     Integration::SetRotationGestureMinimumTouchEventsAfterStart(mEnvironmentOptions->GetMinimumRotationTouchEventsAfterStart());
303   }
304   if(mEnvironmentOptions->GetLongPressMinimumHoldingTime() >= 0)
305   {
306     Integration::SetLongPressMinimumHoldingTime(mEnvironmentOptions->GetLongPressMinimumHoldingTime());
307   }
308   if(mEnvironmentOptions->GetTapMaximumAllowedTime() > 0)
309   {
310     Integration::SetTapMaximumAllowedTime(mEnvironmentOptions->GetTapMaximumAllowedTime());
311   }
312
313   std::string systemCachePath = GetSystemCachePath();
314   if(!systemCachePath.empty())
315   {
316     const int dir_err = mkdir(systemCachePath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
317     if(0 != dir_err && errno != EEXIST)
318     {
319       DALI_LOG_ERROR("Error creating system cache directory: %s!\n", systemCachePath.c_str());
320     }
321   }
322
323   mConfigurationManager = Utils::MakeUnique<ConfigurationManager>(systemCachePath, mGraphics.get(), mThreadController);
324 }
325
326 void Adaptor::AccessibilityObserver::OnAccessibleKeyEvent(const Dali::KeyEvent& event)
327 {
328   Accessibility::KeyEventType type;
329   if(event.GetState() == Dali::KeyEvent::DOWN)
330   {
331     type = Accessibility::KeyEventType::KEY_PRESSED;
332   }
333   else if(event.GetState() == Dali::KeyEvent::UP)
334   {
335     type = Accessibility::KeyEventType::KEY_RELEASED;
336   }
337   else
338   {
339     return;
340   }
341   Dali::Accessibility::Bridge::GetCurrentBridge()->Emit(type, event.GetKeyCode(), event.GetKeyName(), event.GetTime(), !event.GetKeyString().empty());
342 }
343
344 Adaptor::~Adaptor()
345 {
346   Accessibility::Bridge::GetCurrentBridge()->Terminate();
347
348   // Ensure stop status
349   Stop();
350
351   // set to NULL first as we do not want any access to Adaptor as it is being destroyed.
352   gThreadLocalAdaptor = NULL;
353
354   for(ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter)
355   {
356     (*iter)->OnDestroy();
357   }
358
359   // Clear out all the handles to Windows
360   mWindows.clear();
361
362   delete mThreadController; // this will shutdown render thread, which will call Core::ContextDestroyed before exit
363   delete mObjectProfiler;
364
365   delete mCore;
366
367   delete mDisplayConnection;
368   delete mPlatformAbstraction;
369
370   mCallbackManager.reset();
371
372   delete mPerformanceInterface;
373
374   mGraphics->Destroy();
375
376   // uninstall it on this thread (main actor thread)
377   Dali::Integration::Log::UninstallLogFunction();
378
379   // Delete environment options if we own it
380   if(mEnvironmentOptionsOwned)
381   {
382     delete mEnvironmentOptions;
383   }
384 }
385
386 void Adaptor::Start()
387 {
388   // It doesn't support restart after stop at this moment to support restarting, need more testing
389   if(READY != mState)
390   {
391     return;
392   }
393
394   mCore->Initialize();
395
396   SetupSystemInformation();
397
398   // Start the callback manager
399   mCallbackManager->Start();
400
401   // Initialize accessibility bridge after callback manager is started to use Idler callback
402   auto appName = GetApplicationPackageName();
403   auto bridge  = Accessibility::Bridge::GetCurrentBridge();
404   bridge->SetApplicationName(appName);
405   bridge->Initialize();
406   Dali::Stage::GetCurrent().KeyEventSignal().Connect(&mAccessibilityObserver, &AccessibilityObserver::OnAccessibleKeyEvent);
407
408   Dali::Internal::Adaptor::SceneHolder* defaultWindow = mWindows.front();
409
410   unsigned int dpiHor, dpiVer;
411   dpiHor = dpiVer = 0;
412
413   defaultWindow->GetSurface()->GetDpi(dpiHor, dpiVer);
414   Dali::Internal::Adaptor::WindowSystem::SetDpi(dpiHor, dpiVer);
415
416   // Initialize the thread controller
417   mThreadController->Initialize();
418
419   // Set max texture size
420   if(mEnvironmentOptions->GetMaxTextureSize() > 0)
421   {
422     Dali::TizenPlatform::ImageLoader::SetMaxTextureSize(mEnvironmentOptions->GetMaxTextureSize());
423   }
424   else
425   {
426     unsigned int maxTextureSize = mConfigurationManager->GetMaxTextureSize();
427     Dali::TizenPlatform::ImageLoader::SetMaxTextureSize(maxTextureSize);
428   }
429
430   // cache advanced blending and shader language version
431   mGraphics->CacheConfigurations(*mConfigurationManager.get());
432
433   ProcessCoreEvents(); // Ensure any startup messages are processed.
434
435   // Initialize the image loader plugin
436   auto enablePluginString = Dali::EnvironmentVariable::GetEnvironmentVariable(ENABLE_IMAGE_LOADER_PLUGIN_ENV);
437   bool enablePlugin       = enablePluginString ? std::atoi(enablePluginString) : false;
438   if(enablePlugin)
439   {
440     Internal::Adaptor::ImageLoaderPluginProxy::Initialize();
441   }
442
443   for(ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter)
444   {
445     (*iter)->OnStart();
446   }
447
448   if(mAddOnManager)
449   {
450     mAddOnManager->Start();
451   }
452 }
453
454 // Dali::Internal::Adaptor::Adaptor::Pause
455 void Adaptor::Pause()
456 {
457   // Only pause the adaptor if we're actually running.
458   if(RUNNING == mState)
459   {
460     // Inform observers that we are about to be paused.
461     for(ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter)
462     {
463       (*iter)->OnPause();
464     }
465
466     // Extensions
467     if(mAddOnManager)
468     {
469       mAddOnManager->Pause();
470     }
471
472     // Pause all windows event handlers when adaptor paused
473     for(auto window : mWindows)
474     {
475       window->Pause();
476     }
477
478     mThreadController->Pause();
479     mState = PAUSED;
480
481     // Ensure any messages queued during pause callbacks are processed by doing another update.
482     RequestUpdateOnce();
483
484     DALI_LOG_RELEASE_INFO("Adaptor::Pause: Paused\n");
485   }
486   else
487   {
488     DALI_LOG_RELEASE_INFO("Adaptor::Pause: Not paused [%d]\n", mState);
489   }
490 }
491
492 // Dali::Internal::Adaptor::Adaptor::Resume
493 void Adaptor::Resume()
494 {
495   // Only resume the adaptor if we are in the suspended state.
496   if(PAUSED == mState)
497   {
498     mState = RUNNING;
499
500     // Reset the event handlers when adaptor resumed
501     for(auto window : mWindows)
502     {
503       window->Resume();
504     }
505
506     // Resume AddOnManager
507     if(mAddOnManager)
508     {
509       mAddOnManager->Resume();
510     }
511
512     // Inform observers that we have resumed.
513     for(ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter)
514     {
515       (*iter)->OnResume();
516     }
517
518     // Trigger processing of events queued up while paused
519     mCore->ProcessEvents();
520
521     // Do at end to ensure our first update/render after resumption includes the processed messages as well
522     mThreadController->Resume();
523
524     DALI_LOG_RELEASE_INFO("Adaptor::Resume: Resumed\n");
525   }
526   else
527   {
528     DALI_LOG_RELEASE_INFO("Adaptor::Resume: Not resumed [%d]\n", mState);
529   }
530 }
531
532 void Adaptor::Stop()
533 {
534   if(RUNNING == mState ||
535      PAUSED == mState ||
536      PAUSED_WHILE_HIDDEN == mState)
537   {
538     for(ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter)
539     {
540       (*iter)->OnStop();
541     }
542
543     if(mAddOnManager)
544     {
545       mAddOnManager->Stop();
546     }
547
548     mThreadController->Stop();
549
550     // Delete the TTS player
551     for(int i = 0; i < Dali::TtsPlayer::MODE_NUM; i++)
552     {
553       if(mTtsPlayers[i])
554       {
555         mTtsPlayers[i].Reset();
556       }
557     }
558
559     // Destroy the image loader plugin
560     auto enablePluginString = Dali::EnvironmentVariable::GetEnvironmentVariable(ENABLE_IMAGE_LOADER_PLUGIN_ENV);
561     bool enablePlugin       = enablePluginString ? std::atoi(enablePluginString) : false;
562     if(enablePlugin)
563     {
564       Internal::Adaptor::ImageLoaderPluginProxy::Destroy();
565     }
566
567     delete mNotificationTrigger;
568     mNotificationTrigger = NULL;
569
570     mCallbackManager->Stop();
571
572     mState = STOPPED;
573
574     DALI_LOG_RELEASE_INFO("Adaptor::Stop\n");
575   }
576 }
577
578 void Adaptor::ContextLost()
579 {
580   mCore->GetContextNotifier()->NotifyContextLost(); // Inform stage
581 }
582
583 void Adaptor::ContextRegained()
584 {
585   // Inform core, so that texture resources can be reloaded
586   mCore->RecoverFromContextLoss();
587
588   mCore->GetContextNotifier()->NotifyContextRegained(); // Inform stage
589 }
590
591 void Adaptor::FeedTouchPoint(TouchPoint& point, int timeStamp)
592 {
593   Integration::Point convertedPoint(point);
594   mWindows.front()->FeedTouchPoint(convertedPoint, timeStamp);
595 }
596
597 void Adaptor::FeedWheelEvent(Dali::WheelEvent& wheelEvent)
598 {
599   Integration::WheelEvent event(static_cast<Integration::WheelEvent::Type>(wheelEvent.GetType()), wheelEvent.GetDirection(), wheelEvent.GetModifiers(), wheelEvent.GetPoint(), wheelEvent.GetDelta(), wheelEvent.GetTime());
600   mWindows.front()->FeedWheelEvent(event);
601 }
602
603 void Adaptor::FeedKeyEvent(Dali::KeyEvent& keyEvent)
604 {
605   Integration::KeyEvent convertedEvent(keyEvent.GetKeyName(), keyEvent.GetLogicalKey(), keyEvent.GetKeyString(), keyEvent.GetKeyCode(), keyEvent.GetKeyModifier(), keyEvent.GetTime(), static_cast<Integration::KeyEvent::State>(keyEvent.GetState()), keyEvent.GetCompose(), keyEvent.GetDeviceName(), keyEvent.GetDeviceClass(), keyEvent.GetDeviceSubclass());
606   mWindows.front()->FeedKeyEvent(convertedEvent);
607 }
608
609 void Adaptor::ReplaceSurface(Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& newSurface)
610 {
611   Internal::Adaptor::SceneHolder* windowImpl = &Dali::GetImplementation(window);
612   for(auto windowPtr : mWindows)
613   {
614     if(windowPtr == windowImpl) // the window is not deleted
615     {
616       mResizedSignal.Emit(mAdaptor);
617
618       windowImpl->SetSurface(&newSurface);
619
620       // Flush the event queue to give the update-render thread chance
621       // to start processing messages for new camera setup etc as soon as possible
622       ProcessCoreEvents();
623
624       // This method blocks until the render thread has completed the replace.
625       mThreadController->ReplaceSurface(&newSurface);
626       break;
627     }
628   }
629 }
630
631 void Adaptor::DeleteSurface(Dali::RenderSurfaceInterface& surface)
632 {
633   // Flush the event queue to give the update-render thread chance
634   // to start processing messages for new camera setup etc as soon as possible
635   ProcessCoreEvents();
636
637   // This method blocks until the render thread has finished rendering the current surface.
638   mThreadController->DeleteSurface(&surface);
639 }
640
641 Dali::RenderSurfaceInterface& Adaptor::GetSurface() const
642 {
643   return *mWindows.front()->GetSurface();
644 }
645
646 void Adaptor::ReleaseSurfaceLock()
647 {
648   mWindows.front()->GetSurface()->ReleaseLock();
649 }
650
651 Dali::TtsPlayer Adaptor::GetTtsPlayer(Dali::TtsPlayer::Mode mode)
652 {
653   if(!mTtsPlayers[mode])
654   {
655     // Create the TTS player when it needed, because it can reduce launching time.
656     mTtsPlayers[mode] = TtsPlayer::New(mode);
657   }
658
659   return mTtsPlayers[mode];
660 }
661
662 bool Adaptor::AddIdle(CallbackBase* callback, bool hasReturnValue, bool forceAdd)
663 {
664   bool idleAdded(false);
665
666   // Only add an idle if the Adaptor is actually running
667   if(RUNNING == mState || READY == mState || forceAdd)
668   {
669     idleAdded = mCallbackManager->AddIdleCallback(callback, hasReturnValue);
670   }
671
672   return idleAdded;
673 }
674
675 void Adaptor::RemoveIdle(CallbackBase* callback)
676 {
677   mCallbackManager->RemoveIdleCallback(callback);
678 }
679
680 void Adaptor::ProcessIdle()
681 {
682   bool idleProcessed           = mCallbackManager->ProcessIdle();
683   mNotificationOnIdleInstalled = mNotificationOnIdleInstalled && !idleProcessed;
684 }
685
686 void Adaptor::SetPreRenderCallback(CallbackBase* callback)
687 {
688   mThreadController->SetPreRenderCallback(callback);
689 }
690
691 bool Adaptor::AddWindow(Dali::Integration::SceneHolder childWindow)
692 {
693   Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation(childWindow);
694   windowImpl.SetAdaptor(Get());
695
696   // ChildWindow is set to the layout direction of the default window.
697   windowImpl.GetRootLayer().SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, mRootLayoutDirection);
698
699   // Add the new Window to the container - the order is not important
700   {
701     Dali::Mutex::ScopedLock lock(mMutex);
702     mWindows.push_back(&windowImpl);
703   }
704
705   Dali::RenderSurfaceInterface* surface = windowImpl.GetSurface();
706
707   mThreadController->AddSurface(surface);
708
709   mWindowCreatedSignal.Emit(childWindow);
710
711   return true;
712 }
713
714 bool Adaptor::RemoveWindow(Dali::Integration::SceneHolder* childWindow)
715 {
716   Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation(*childWindow);
717   for(WindowContainer::iterator iter = mWindows.begin(); iter != mWindows.end(); ++iter)
718   {
719     if(*iter == &windowImpl)
720     {
721       Dali::Mutex::ScopedLock lock(mMutex);
722       mWindows.erase(iter);
723       return true;
724     }
725   }
726
727   return false;
728 }
729
730 bool Adaptor::RemoveWindow(std::string childWindowName)
731 {
732   for(WindowContainer::iterator iter = mWindows.begin(); iter != mWindows.end(); ++iter)
733   {
734     if((*iter)->GetName() == childWindowName)
735     {
736       Dali::Mutex::ScopedLock lock(mMutex);
737       mWindows.erase(iter);
738       return true;
739     }
740   }
741
742   return false;
743 }
744
745 bool Adaptor::RemoveWindow(Internal::Adaptor::SceneHolder* childWindow)
746 {
747   for(WindowContainer::iterator iter = mWindows.begin(); iter != mWindows.end(); ++iter)
748   {
749     if((*iter)->GetId() == childWindow->GetId())
750     {
751       Dali::Mutex::ScopedLock lock(mMutex);
752       mWindows.erase(iter);
753       return true;
754     }
755   }
756
757   return false;
758 }
759
760 Dali::Adaptor& Adaptor::Get()
761 {
762   DALI_ASSERT_ALWAYS(IsAvailable() && "Adaptor not instantiated");
763   return gThreadLocalAdaptor->mAdaptor;
764 }
765
766 bool Adaptor::IsAvailable()
767 {
768   return gThreadLocalAdaptor != NULL;
769 }
770
771 void Adaptor::SceneCreated()
772 {
773   mCore->SceneCreated();
774 }
775
776 Dali::Integration::Core& Adaptor::GetCore()
777 {
778   return *mCore;
779 }
780
781 void Adaptor::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender)
782 {
783   mThreadController->SetRenderRefreshRate(numberOfVSyncsPerRender);
784 }
785
786 Dali::DisplayConnection& Adaptor::GetDisplayConnectionInterface()
787 {
788   DALI_ASSERT_DEBUG(mDisplayConnection && "Display connection not created");
789   return *mDisplayConnection;
790 }
791
792 GraphicsInterface& Adaptor::GetGraphicsInterface()
793 {
794   DALI_ASSERT_DEBUG(mGraphics && "Graphics interface not created");
795   return *(mGraphics.get());
796 }
797
798 Dali::Integration::PlatformAbstraction& Adaptor::GetPlatformAbstractionInterface()
799 {
800   return *mPlatformAbstraction;
801 }
802
803 TriggerEventInterface& Adaptor::GetProcessCoreEventsTrigger()
804 {
805   return *mNotificationTrigger;
806 }
807
808 SocketFactoryInterface& Adaptor::GetSocketFactoryInterface()
809 {
810   return mSocketFactory;
811 }
812
813 Dali::RenderSurfaceInterface* Adaptor::GetRenderSurfaceInterface()
814 {
815   if(!mWindows.empty())
816   {
817     return mWindows.front()->GetSurface();
818   }
819
820   return nullptr;
821 }
822
823 TraceInterface& Adaptor::GetKernelTraceInterface()
824 {
825   return mKernelTracer;
826 }
827
828 TraceInterface& Adaptor::GetSystemTraceInterface()
829 {
830   return mSystemTracer;
831 }
832
833 PerformanceInterface* Adaptor::GetPerformanceInterface()
834 {
835   return mPerformanceInterface;
836 }
837
838 Integration::PlatformAbstraction& Adaptor::GetPlatformAbstraction() const
839 {
840   DALI_ASSERT_DEBUG(mPlatformAbstraction && "PlatformAbstraction not created");
841   return *mPlatformAbstraction;
842 }
843
844 void Adaptor::GetWindowContainerInterface(WindowContainer& windows)
845 {
846   Dali::Mutex::ScopedLock lock(mMutex);
847   windows = mWindows;
848 }
849
850 void Adaptor::DestroyTtsPlayer(Dali::TtsPlayer::Mode mode)
851 {
852   if(mTtsPlayers[mode])
853   {
854     mTtsPlayers[mode].Reset();
855   }
856 }
857
858 Any Adaptor::GetNativeWindowHandle()
859 {
860   return mWindows.front()->GetNativeHandle();
861 }
862
863 Any Adaptor::GetNativeWindowHandle(Dali::Actor actor)
864 {
865   Any nativeWindowHandle;
866
867   Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor);
868
869   for(auto sceneHolder : mWindows)
870   {
871     if(scene == sceneHolder->GetScene())
872     {
873       nativeWindowHandle = sceneHolder->GetNativeHandle();
874       break;
875     }
876   }
877
878   return nativeWindowHandle;
879 }
880
881 Any Adaptor::GetGraphicsDisplay()
882 {
883   Any display;
884
885   if(mGraphics)
886   {
887     GraphicsInterface* graphics    = mGraphics.get(); // This interface is temporary until Core has been updated to match
888     auto               eglGraphics = static_cast<EglGraphics*>(graphics);
889
890     EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
891     display                    = eglImpl.GetDisplay();
892   }
893
894   return display;
895 }
896
897 void Adaptor::SetUseRemoteSurface(bool useRemoteSurface)
898 {
899   mUseRemoteSurface = useRemoteSurface;
900 }
901
902 void Adaptor::AddObserver(LifeCycleObserver& observer)
903 {
904   ObserverContainer::iterator match(find(mObservers.begin(), mObservers.end(), &observer));
905
906   if(match == mObservers.end())
907   {
908     mObservers.push_back(&observer);
909   }
910 }
911
912 void Adaptor::RemoveObserver(LifeCycleObserver& observer)
913 {
914   ObserverContainer::iterator match(find(mObservers.begin(), mObservers.end(), &observer));
915
916   if(match != mObservers.end())
917   {
918     mObservers.erase(match);
919   }
920 }
921
922 void Adaptor::QueueCoreEvent(const Dali::Integration::Event& event)
923 {
924   if(mCore)
925   {
926     mCore->QueueEvent(event);
927   }
928 }
929
930 void Adaptor::ProcessCoreEvents()
931 {
932   if(mCore)
933   {
934     DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_CORE_EVENTS");
935
936     if(mPerformanceInterface)
937     {
938       mPerformanceInterface->AddMarker(PerformanceInterface::PROCESS_EVENTS_START);
939     }
940
941     mCore->ProcessEvents();
942
943     if(mPerformanceInterface)
944     {
945       mPerformanceInterface->AddMarker(PerformanceInterface::PROCESS_EVENTS_END);
946     }
947   }
948 }
949
950 void Adaptor::RequestUpdate()
951 {
952   switch(mState)
953   {
954     case RUNNING:
955     {
956       mThreadController->RequestUpdate();
957       break;
958     }
959     case PAUSED:
960     case PAUSED_WHILE_HIDDEN:
961     {
962       // Update (and resource upload) without rendering
963       mThreadController->RequestUpdateOnce(UpdateMode::SKIP_RENDER);
964       break;
965     }
966     default:
967     {
968       // Do nothing
969       break;
970     }
971   }
972 }
973
974 void Adaptor::RequestProcessEventsOnIdle()
975 {
976   // We want to run the processes even when paused
977   if(STOPPED != mState)
978   {
979     if(!mNotificationOnIdleInstalled)
980     {
981       // If we haven't installed the idle notification, install it idle enterer.
982       mNotificationOnIdleInstalled = AddIdleEnterer(MakeCallback(this, &Adaptor::ProcessCoreEventsFromIdle), true);
983     }
984     else
985     {
986       // Request comes during ProcessCoreEventsFromIdle running.
987       // Mark as we need to call ProcessEvents in next idle events.
988       mRequiredIdleRepeat = true;
989     }
990   }
991 }
992
993 void Adaptor::OnWindowShown()
994 {
995   if(PAUSED_WHILE_HIDDEN == mState)
996   {
997     // Adaptor can now be resumed
998     mState = PAUSED;
999
1000     Resume();
1001
1002     // Force a render task
1003     RequestUpdateOnce();
1004   }
1005   else if(RUNNING == mState)
1006   {
1007     // Force a render task
1008     RequestUpdateOnce();
1009
1010     DALI_LOG_RELEASE_INFO("Adaptor::OnWindowShown: Update requested.\n");
1011   }
1012   else if(PAUSED_WHILE_INITIALIZING == mState)
1013   {
1014     // Change the state to READY again. It will be changed to RUNNING after the adaptor is started.
1015     mState = READY;
1016   }
1017   else
1018   {
1019     DALI_LOG_RELEASE_INFO("Adaptor::OnWindowShown: Adaptor is not paused state.[%d]\n", mState);
1020   }
1021 }
1022
1023 void Adaptor::OnWindowHidden()
1024 {
1025   if(RUNNING == mState || READY == mState)
1026   {
1027     bool allWindowsHidden = true;
1028
1029     for(auto window : mWindows)
1030     {
1031       if(window->IsVisible())
1032       {
1033         allWindowsHidden = false;
1034         break;
1035       }
1036     }
1037
1038     // Only pause the adaptor when all the windows are hidden
1039     if(allWindowsHidden)
1040     {
1041       if(mState == RUNNING)
1042       {
1043         Pause();
1044
1045         // Adaptor cannot be resumed until any window is shown
1046         mState = PAUSED_WHILE_HIDDEN;
1047       }
1048       else // mState is READY
1049       {
1050         // Pause the adaptor after the state gets RUNNING
1051         mState = PAUSED_WHILE_INITIALIZING;
1052       }
1053     }
1054     else
1055     {
1056       DALI_LOG_RELEASE_INFO("Adaptor::OnWindowHidden: Some windows are shown. Don't pause adaptor.\n");
1057     }
1058   }
1059   else
1060   {
1061     DALI_LOG_RELEASE_INFO("Adaptor::OnWindowHidden: Adaptor is not running state.[%d]\n", mState);
1062   }
1063 }
1064
1065 // Dali::Internal::Adaptor::Adaptor::OnDamaged
1066 void Adaptor::OnDamaged(const DamageArea& area)
1067 {
1068   // This is needed for the case where Dali window is partially obscured
1069   RequestUpdate();
1070 }
1071
1072 void Adaptor::SurfaceResizePrepare(Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize)
1073 {
1074   mResizedSignal.Emit(mAdaptor);
1075 }
1076
1077 void Adaptor::SurfaceResizeComplete(Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize)
1078 {
1079   // Nofify surface resizing before flushing event queue
1080   mThreadController->ResizeSurface();
1081
1082   // Flush the event queue to give the update-render thread chance
1083   // to start processing messages for new camera setup etc as soon as possible
1084   ProcessCoreEvents();
1085 }
1086
1087 void Adaptor::NotifySceneCreated()
1088 {
1089   GetCore().SceneCreated();
1090
1091   // Flush the event queue to give the update-render thread chance
1092   // to start processing messages for new camera setup etc as soon as possible
1093   ProcessCoreEvents();
1094
1095   // Start thread controller after the scene has been created
1096   mThreadController->Start();
1097
1098   // Process after surface is created (registering to remote surface provider if required)
1099   SurfaceInitialized();
1100
1101   if(mState != PAUSED_WHILE_INITIALIZING)
1102   {
1103     mState = RUNNING;
1104
1105     DALI_LOG_RELEASE_INFO("Adaptor::NotifySceneCreated: Adaptor is running\n");
1106   }
1107   else
1108   {
1109     mState = RUNNING;
1110
1111     Pause();
1112
1113     mState = PAUSED_WHILE_HIDDEN;
1114
1115     DALI_LOG_RELEASE_INFO("Adaptor::NotifySceneCreated: Adaptor is paused\n");
1116   }
1117 }
1118
1119 void Adaptor::NotifyLanguageChanged()
1120 {
1121   mLanguageChangedSignal.Emit(mAdaptor);
1122 }
1123
1124 void Adaptor::RenderOnce()
1125 {
1126   if(mThreadController)
1127   {
1128     UpdateMode updateMode;
1129     if(mThreadMode == ThreadMode::NORMAL)
1130     {
1131       updateMode = UpdateMode::NORMAL;
1132     }
1133     else
1134     {
1135       updateMode = UpdateMode::FORCE_RENDER;
1136
1137       ProcessCoreEvents();
1138     }
1139     mThreadController->RequestUpdateOnce(updateMode);
1140   }
1141 }
1142
1143 const LogFactoryInterface& Adaptor::GetLogFactory()
1144 {
1145   return *mEnvironmentOptions;
1146 }
1147
1148 void Adaptor::RegisterProcessor(Integration::Processor& processor, bool postProcessor)
1149 {
1150   GetCore().RegisterProcessor(processor, postProcessor);
1151 }
1152
1153 void Adaptor::UnregisterProcessor(Integration::Processor& processor, bool postProcessor)
1154 {
1155   GetCore().UnregisterProcessor(processor, postProcessor);
1156 }
1157
1158 bool Adaptor::IsMultipleWindowSupported() const
1159 {
1160   return mConfigurationManager->IsMultipleWindowSupported();
1161 }
1162
1163 int32_t Adaptor::GetRenderThreadId() const
1164 {
1165   if(mThreadController)
1166   {
1167     return mThreadController->GetThreadId();
1168   }
1169   return 0;
1170 }
1171
1172 void Adaptor::RequestUpdateOnce()
1173 {
1174   if(mThreadController)
1175   {
1176     mThreadController->RequestUpdateOnce(UpdateMode::NORMAL);
1177   }
1178 }
1179
1180 bool Adaptor::ProcessCoreEventsFromIdle()
1181 {
1182   // Reset repeat idler flag.
1183   mRequiredIdleRepeat = false;
1184   ProcessCoreEvents();
1185
1186   // If someone request ProcessCoreEvents during above ProcessCoreEvents call, we might need to run idle one more times.
1187   // Else, the idle handle automatically un-installs itself
1188   mNotificationOnIdleInstalled = mRequiredIdleRepeat;
1189
1190   if(mRequiredIdleRepeat)
1191   {
1192     DALI_LOG_DEBUG_INFO("Required ProcessCoreEvents one more times\n");
1193   }
1194
1195   return mRequiredIdleRepeat;
1196 }
1197
1198 Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow(Dali::Actor& actor)
1199 {
1200   Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor);
1201
1202   for(auto window : mWindows)
1203   {
1204     if(scene == window->GetScene())
1205     {
1206       return window;
1207     }
1208   }
1209
1210   return nullptr;
1211 }
1212
1213 Dali::WindowContainer Adaptor::GetWindows() const
1214 {
1215   Dali::WindowContainer windows;
1216
1217   for(auto iter = mWindows.begin(); iter != mWindows.end(); ++iter)
1218   {
1219     // Downcast to Dali::Window
1220     Dali::Window window(dynamic_cast<Dali::Internal::Adaptor::Window*>(*iter));
1221     if(window)
1222     {
1223       windows.push_back(window);
1224     }
1225   }
1226
1227   return windows;
1228 }
1229
1230 Dali::SceneHolderList Adaptor::GetSceneHolders() const
1231 {
1232   Dali::SceneHolderList sceneHolderList;
1233
1234   for(auto iter = mWindows.begin(); iter != mWindows.end(); ++iter)
1235   {
1236     sceneHolderList.push_back(Dali::Integration::SceneHolder(*iter));
1237   }
1238
1239   return sceneHolderList;
1240 }
1241
1242 Dali::ObjectRegistry Adaptor::GetObjectRegistry() const
1243 {
1244   Dali::ObjectRegistry registry;
1245   if(mCore)
1246   {
1247     registry = mCore->GetObjectRegistry();
1248   }
1249   return registry;
1250 }
1251
1252 Adaptor::Adaptor(Dali::Integration::SceneHolder window, Dali::Adaptor& adaptor, Dali::RenderSurfaceInterface* surface, EnvironmentOptions* environmentOptions, ThreadMode threadMode)
1253 : mResizedSignal(),
1254   mLanguageChangedSignal(),
1255   mWindowCreatedSignal(),
1256   mAdaptor(adaptor),
1257   mState(READY),
1258   mCore(nullptr),
1259   mThreadController(nullptr),
1260   mGraphics(nullptr),
1261   mDisplayConnection(nullptr),
1262   mWindows(),
1263   mConfigurationManager(nullptr),
1264   mPlatformAbstraction(nullptr),
1265   mCallbackManager(nullptr),
1266   mNotificationOnIdleInstalled(false),
1267   mRequiredIdleRepeat(false),
1268   mNotificationTrigger(nullptr),
1269   mDaliFeedbackPlugin(),
1270   mFeedbackController(nullptr),
1271   mTtsPlayers(),
1272   mObservers(),
1273   mEnvironmentOptions(environmentOptions ? environmentOptions : new EnvironmentOptions /* Create the options if not provided */),
1274   mPerformanceInterface(nullptr),
1275   mKernelTracer(),
1276   mSystemTracer(),
1277   mObjectProfiler(nullptr),
1278   mMemoryPoolTimerSlotDelegate(this),
1279   mSocketFactory(),
1280   mMutex(),
1281   mThreadMode(threadMode),
1282   mEnvironmentOptionsOwned(environmentOptions ? false : true /* If not provided then we own the object */),
1283   mUseRemoteSurface(false),
1284   mRootLayoutDirection(Dali::LayoutDirection::LEFT_TO_RIGHT)
1285 {
1286   DALI_ASSERT_ALWAYS(!IsAvailable() && "Cannot create more than one Adaptor per thread");
1287   mWindows.insert(mWindows.begin(), &Dali::GetImplementation(window));
1288
1289   gThreadLocalAdaptor = this;
1290 }
1291
1292 void Adaptor::SetRootLayoutDirection(std::string locale)
1293 {
1294   mRootLayoutDirection = static_cast<LayoutDirection::Type>(Internal::Adaptor::Locale::GetDirection(std::string(locale)));
1295   for(auto& window : mWindows)
1296   {
1297     Dali::Actor root = window->GetRootLayer();
1298     root.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, mRootLayoutDirection);
1299   }
1300 }
1301
1302 bool Adaptor::AddIdleEnterer(CallbackBase* callback, bool forceAdd)
1303 {
1304   bool idleAdded(false);
1305
1306   // Only add an idle if the Adaptor is actually running
1307   if(RUNNING == mState || READY == mState || forceAdd)
1308   {
1309     idleAdded = mCallbackManager->AddIdleEntererCallback(callback);
1310   }
1311
1312   if(!idleAdded)
1313   {
1314     // Delete callback
1315     delete callback;
1316   }
1317
1318   return idleAdded;
1319 }
1320
1321 void Adaptor::RemoveIdleEnterer(CallbackBase* callback)
1322 {
1323   mCallbackManager->RemoveIdleEntererCallback(callback);
1324 }
1325
1326 bool Adaptor::MemoryPoolTimeout()
1327 {
1328   mCore->LogMemoryPools();
1329   return true; // Keep logging forever
1330 }
1331
1332 } // namespace Adaptor
1333
1334 } // namespace Internal
1335
1336 } // namespace Dali