af57022b0f3370a50b2534147ba29f0c83d9da17
[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/graphics/common/egl-image-extensions.h>
59 #include <dali/internal/graphics/gles/egl-sync-implementation.h>
60 #include <dali/internal/graphics/gles/gl-implementation.h>
61 #include <dali/internal/graphics/gles/gl-proxy-implementation.h>
62 #include <dali/internal/system/common/callback-manager.h>
63 #include <dali/internal/system/common/object-profiler.h>
64 #include <dali/internal/system/common/system-factory.h>
65 #include <dali/internal/text-clipboard/common/text-clipboard-impl.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
1140     // Force rendering
1141     for(auto&& iter : mWindows)
1142     {
1143       iter->GetSurface()->SetFullSwapNextFrame();
1144     }
1145
1146     mThreadController->RequestUpdateOnce(updateMode);
1147   }
1148 }
1149
1150 const LogFactoryInterface& Adaptor::GetLogFactory()
1151 {
1152   return *mEnvironmentOptions;
1153 }
1154
1155 void Adaptor::RegisterProcessor(Integration::Processor& processor, bool postProcessor)
1156 {
1157   GetCore().RegisterProcessor(processor, postProcessor);
1158 }
1159
1160 void Adaptor::UnregisterProcessor(Integration::Processor& processor, bool postProcessor)
1161 {
1162   GetCore().UnregisterProcessor(processor, postProcessor);
1163 }
1164
1165 bool Adaptor::IsMultipleWindowSupported() const
1166 {
1167   return mConfigurationManager->IsMultipleWindowSupported();
1168 }
1169
1170 int32_t Adaptor::GetRenderThreadId() const
1171 {
1172   if(mThreadController)
1173   {
1174     return mThreadController->GetThreadId();
1175   }
1176   return 0;
1177 }
1178
1179 void Adaptor::RequestUpdateOnce()
1180 {
1181   if(mThreadController)
1182   {
1183     mThreadController->RequestUpdateOnce(UpdateMode::NORMAL);
1184   }
1185 }
1186
1187 bool Adaptor::ProcessCoreEventsFromIdle()
1188 {
1189   // Reset repeat idler flag.
1190   mRequiredIdleRepeat = false;
1191   ProcessCoreEvents();
1192
1193   // If someone request ProcessCoreEvents during above ProcessCoreEvents call, we might need to run idle one more times.
1194   // Else, the idle handle automatically un-installs itself
1195   mNotificationOnIdleInstalled = mRequiredIdleRepeat;
1196
1197   if(mRequiredIdleRepeat)
1198   {
1199     DALI_LOG_DEBUG_INFO("Required ProcessCoreEvents one more times\n");
1200   }
1201
1202   return mRequiredIdleRepeat;
1203 }
1204
1205 Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow(Dali::Actor& actor)
1206 {
1207   Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor);
1208
1209   for(auto window : mWindows)
1210   {
1211     if(scene == window->GetScene())
1212     {
1213       return window;
1214     }
1215   }
1216
1217   return nullptr;
1218 }
1219
1220 Dali::WindowContainer Adaptor::GetWindows() const
1221 {
1222   Dali::WindowContainer windows;
1223
1224   for(auto iter = mWindows.begin(); iter != mWindows.end(); ++iter)
1225   {
1226     // Downcast to Dali::Window
1227     Dali::Window window(dynamic_cast<Dali::Internal::Adaptor::Window*>(*iter));
1228     if(window)
1229     {
1230       windows.push_back(window);
1231     }
1232   }
1233
1234   return windows;
1235 }
1236
1237 Dali::SceneHolderList Adaptor::GetSceneHolders() const
1238 {
1239   Dali::SceneHolderList sceneHolderList;
1240
1241   for(auto iter = mWindows.begin(); iter != mWindows.end(); ++iter)
1242   {
1243     sceneHolderList.push_back(Dali::Integration::SceneHolder(*iter));
1244   }
1245
1246   return sceneHolderList;
1247 }
1248
1249 Dali::ObjectRegistry Adaptor::GetObjectRegistry() const
1250 {
1251   Dali::ObjectRegistry registry;
1252   if(mCore)
1253   {
1254     registry = mCore->GetObjectRegistry();
1255   }
1256   return registry;
1257 }
1258
1259 Adaptor::Adaptor(Dali::Integration::SceneHolder window, Dali::Adaptor& adaptor, Dali::RenderSurfaceInterface* surface, EnvironmentOptions* environmentOptions, ThreadMode threadMode)
1260 : mResizedSignal(),
1261   mLanguageChangedSignal(),
1262   mWindowCreatedSignal(),
1263   mAdaptor(adaptor),
1264   mState(READY),
1265   mCore(nullptr),
1266   mThreadController(nullptr),
1267   mGraphics(nullptr),
1268   mDisplayConnection(nullptr),
1269   mWindows(),
1270   mConfigurationManager(nullptr),
1271   mPlatformAbstraction(nullptr),
1272   mCallbackManager(nullptr),
1273   mNotificationOnIdleInstalled(false),
1274   mRequiredIdleRepeat(false),
1275   mNotificationTrigger(nullptr),
1276   mDaliFeedbackPlugin(),
1277   mFeedbackController(nullptr),
1278   mTtsPlayers(),
1279   mObservers(),
1280   mEnvironmentOptions(environmentOptions ? environmentOptions : new EnvironmentOptions /* Create the options if not provided */),
1281   mPerformanceInterface(nullptr),
1282   mKernelTracer(),
1283   mSystemTracer(),
1284   mObjectProfiler(nullptr),
1285   mMemoryPoolTimerSlotDelegate(this),
1286   mSocketFactory(),
1287   mMutex(),
1288   mThreadMode(threadMode),
1289   mEnvironmentOptionsOwned(environmentOptions ? false : true /* If not provided then we own the object */),
1290   mUseRemoteSurface(false),
1291   mRootLayoutDirection(Dali::LayoutDirection::LEFT_TO_RIGHT)
1292 {
1293   DALI_ASSERT_ALWAYS(!IsAvailable() && "Cannot create more than one Adaptor per thread");
1294   mWindows.insert(mWindows.begin(), &Dali::GetImplementation(window));
1295
1296   gThreadLocalAdaptor = this;
1297 }
1298
1299 void Adaptor::SetRootLayoutDirection(std::string locale)
1300 {
1301   mRootLayoutDirection = static_cast<LayoutDirection::Type>(Internal::Adaptor::Locale::GetDirection(std::string(locale)));
1302   for(auto& window : mWindows)
1303   {
1304     Dali::Actor root = window->GetRootLayer();
1305     root.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, mRootLayoutDirection);
1306   }
1307 }
1308
1309 bool Adaptor::AddIdleEnterer(CallbackBase* callback, bool forceAdd)
1310 {
1311   bool idleAdded(false);
1312
1313   // Only add an idle if the Adaptor is actually running
1314   if(RUNNING == mState || READY == mState || forceAdd)
1315   {
1316     idleAdded = mCallbackManager->AddIdleEntererCallback(callback);
1317   }
1318
1319   if(!idleAdded)
1320   {
1321     // Delete callback
1322     delete callback;
1323   }
1324
1325   return idleAdded;
1326 }
1327
1328 void Adaptor::RemoveIdleEnterer(CallbackBase* callback)
1329 {
1330   mCallbackManager->RemoveIdleEntererCallback(callback);
1331 }
1332
1333 bool Adaptor::MemoryPoolTimeout()
1334 {
1335   mCore->LogMemoryPools();
1336   return true; // Keep logging forever
1337 }
1338
1339 } // namespace Adaptor
1340
1341 } // namespace Internal
1342
1343 } // namespace Dali