13a5fe604ff50b05f5284a61082e728c803a3bf3
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / application-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/application-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/singleton-service.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/integration-api/trace.h>
25 #include <dali/public-api/object/object-registry.h>
26
27 // INTERNAL INCLUDES
28 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
29 #include <dali/devel-api/adaptor-framework/environment-variable.h>
30 #include <dali/devel-api/adaptor-framework/style-monitor.h>
31 #include <dali/devel-api/atspi-interfaces/accessible.h>
32 #include <dali/devel-api/text-abstraction/font-client.h>
33 #include <dali/internal/adaptor/common/adaptor-impl.h>
34 #include <dali/internal/adaptor/common/framework-factory.h>
35 #include <dali/internal/adaptor/common/framework.h>
36 #include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
37 #include <dali/internal/system/common/command-line-options.h>
38 #include <dali/internal/system/common/environment-variables.h>
39 #include <dali/internal/system/common/system-settings.h>
40 #include <dali/internal/window-system/common/render-surface-factory.h>
41 #include <dali/internal/window-system/common/window-impl.h>
42 #include <dali/internal/window-system/common/window-render-surface.h>
43 #include <dali/internal/window-system/common/window-system.h>
44
45 // To disable a macro with the same name from one of OpenGL headers
46 #undef Status
47
48 namespace Dali
49 {
50 namespace TizenPlatform
51 {
52 class TizenPlatformAbstraction;
53 }
54
55 namespace Integration
56 {
57 class Core;
58 }
59
60 namespace Internal
61 {
62 namespace Adaptor
63 {
64 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_APPLICATION, true);
65
66 ApplicationPtr Application::gPreInitializedApplication(NULL);
67
68 ApplicationPtr Application::New(
69   int*               argc,
70   char**             argv[],
71   const std::string& stylesheet,
72   Framework::Type    applicationType,
73   bool               useUiThread,
74   const WindowData&  windowData)
75 {
76   ApplicationPtr application(new Application(argc, argv, stylesheet, applicationType, useUiThread, windowData));
77   return application;
78 }
79
80 void Application::PreInitialize(int* argc, char** argv[])
81 {
82   if(!gPreInitializedApplication)
83   {
84     char* retEnv        = std::getenv("TIZEN_UI_THREAD");
85     bool  isUseUIThread = false;
86     if(retEnv)
87     {
88       std::string uiThreadEnv   = retEnv;
89       std::string enabledString = "true";
90       if(uiThreadEnv == enabledString)
91       {
92         isUseUIThread = true;
93       }
94     }
95
96     Dali::TextAbstraction::FontClientPreInitialize();
97     WindowData windowData;
98     gPreInitializedApplication                  = new Application(argc, argv, "", Framework::NORMAL, isUseUIThread, windowData);
99     gPreInitializedApplication->mLaunchpadState = Launchpad::PRE_INITIALIZED;
100     if(isUseUIThread)
101     {
102       DALI_LOG_RELEASE_INFO("PRE_INITIALIZED with UI Threading");
103       gPreInitializedApplication->mUIThreadLoader = new UIThreadLoader(argc, argv);
104       gPreInitializedApplication->mUIThreadLoader->Run([&]() { gPreInitializedApplication->CreateWindow(); });
105     }
106     else
107     {
108       DALI_LOG_RELEASE_INFO("Only PRE_INITIALIZED");
109       gPreInitializedApplication->CreateWindow(); // Only create window
110     }
111   }
112 }
113
114 Application::Application(int* argc, char** argv[], const std::string& stylesheet, Framework::Type applicationType, bool useUiThread, const WindowData& windowData)
115 : mInitSignal(),
116   mTerminateSignal(),
117   mPauseSignal(),
118   mResumeSignal(),
119   mResetSignal(),
120   mAppControlSignal(),
121   mLanguageChangedSignal(),
122   mRegionChangedSignal(),
123   mFramework(nullptr),
124   mFrameworkFactory(nullptr),
125   mCommandLineOptions(nullptr),
126   mAdaptorBuilder(nullptr),
127   mAdaptor(nullptr),
128   mEnvironmentOptions(nullptr),
129   mMainWindow(),
130   mMainWindowMode(windowData.GetTransparency() ? WINDOW_MODE::TRANSPARENT : WINDOW_MODE::OPAQUE),
131   mMainWindowName(),
132   mStylesheet(stylesheet),
133   mWindowPositionSize(windowData.GetPositionSize()),
134   mLaunchpadState(Launchpad::NONE),
135   mDefaultWindowType(windowData.GetWindowType()),
136   mUseUiThread(useUiThread),
137   mIsSystemInitialized(false),
138   mSlotDelegate(this),
139   mUIThreadLoader(nullptr)
140 {
141   // Set mName from command-line args
142   if(argc && (*argc > 0))
143   {
144     mMainWindowName = (*argv)[0];
145   }
146
147   const char* uiThreadEnabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_ENABLE_UI_THREAD);
148   if(uiThreadEnabled && std::atoi(uiThreadEnabled) != 0)
149   {
150     mUseUiThread = true;
151   }
152
153   mCommandLineOptions = new CommandLineOptions(argc, argv);
154
155   mFrameworkFactory = std::unique_ptr<FrameworkFactory>(Dali::Internal::Adaptor::CreateFrameworkFactory());
156   mFramework        = mFrameworkFactory->CreateFramework(FrameworkBackend::DEFAULT, *this, *this, argc, argv, applicationType, mUseUiThread);
157
158   mUseRemoteSurface = (applicationType == Framework::WATCH);
159 }
160
161 Application::~Application()
162 {
163   SingletonService service = SingletonService::Get();
164   // Note this can be false i.e. if Application has never created a Core instance
165   if(service)
166   {
167     service.UnregisterAll();
168   }
169
170   mMainWindow.Reset();
171
172   delete mCommandLineOptions;
173
174   // Application is created in Main thread whether UI Threading is enabled or not.
175   // But some resources are created in Main thread or UI thread.
176   // The below code is for the resource are created in Main thread.
177   if(!mUseUiThread)
178   {
179     delete mAdaptor;
180     delete mAdaptorBuilder;
181     if(mIsSystemInitialized)
182     {
183       WindowSystem::Shutdown();
184     }
185   }
186   else
187   {
188     if(mUIThreadLoader)
189     {
190       delete mUIThreadLoader;
191     }
192   }
193 }
194
195 void Application::StoreWindowPositionSize(PositionSize positionSize)
196 {
197   mWindowPositionSize = positionSize;
198 }
199
200 void Application::ChangePreInitializedWindowInfo()
201 {
202   // Set window name
203   auto windowClassName = mEnvironmentOptions->GetWindowClassName();
204   auto windowName      = mEnvironmentOptions->GetWindowName();
205   if(!windowName.empty())
206   {
207     mMainWindowName = windowName;
208   }
209   mMainWindow.SetClass(mMainWindowName, windowClassName);
210
211   // The real screen size may be different from the value of the preinitialized state. Update it.
212   Dali::Internal::Adaptor::WindowSystem::UpdateScreenSize();
213
214   int screenWidth, screenHeight;
215   Dali::Internal::Adaptor::WindowSystem::GetScreenSize(screenWidth, screenHeight);
216
217   // Set window position / size
218   if(mWindowPositionSize != PositionSize(0, 0, 0, 0))
219   {
220     Dali::DevelWindow::SetPositionSize(mMainWindow, mWindowPositionSize);
221   }
222   else if(mCommandLineOptions->stageWidth > 0 && mCommandLineOptions->stageHeight > 0)
223   {
224     // Command line options override environment options and full screen
225     mWindowPositionSize.width  = mCommandLineOptions->stageWidth;
226     mWindowPositionSize.height = mCommandLineOptions->stageHeight;
227     mMainWindow.SetSize(Dali::Window::WindowSize(mWindowPositionSize.width, mWindowPositionSize.height));
228   }
229   else if(mEnvironmentOptions->GetWindowWidth() && mEnvironmentOptions->GetWindowHeight())
230   {
231     // Environment options override full screen functionality if command line arguments not provided
232     mWindowPositionSize.width  = mEnvironmentOptions->GetWindowWidth();
233     mWindowPositionSize.height = mEnvironmentOptions->GetWindowHeight();
234     mMainWindow.SetSize(Dali::Window::WindowSize(mWindowPositionSize.width, mWindowPositionSize.height));
235   }
236   else if(screenWidth != mWindowPositionSize.width || screenHeight != mWindowPositionSize.height)
237   {
238     // Some apps can receive screen size differently after launching by specifying size in manifest.
239     mWindowPositionSize.width  = screenWidth;
240     mWindowPositionSize.height = screenHeight;
241     mMainWindow.SetSize(Dali::Window::WindowSize(mWindowPositionSize.width, mWindowPositionSize.height));
242   }
243 }
244
245 void Application::CreateWindow()
246 {
247   Internal::Adaptor::Window* window;
248   WindowData                 windowData;
249   windowData.SetTransparency(mMainWindowMode);
250   windowData.SetWindowType(mDefaultWindowType);
251
252   DALI_LOG_RELEASE_INFO("Create Default Window");
253
254   WindowSystem::Initialize();
255   mIsSystemInitialized = true;
256
257   if(mLaunchpadState != Launchpad::PRE_INITIALIZED)
258   {
259     if(mWindowPositionSize.width == 0 && mWindowPositionSize.height == 0)
260     {
261       if(mCommandLineOptions->stageWidth > 0 && mCommandLineOptions->stageHeight > 0)
262       {
263         // Command line options override environment options and full screen
264         mWindowPositionSize.width  = mCommandLineOptions->stageWidth;
265         mWindowPositionSize.height = mCommandLineOptions->stageHeight;
266       }
267       else if(mEnvironmentOptions->GetWindowWidth() && mEnvironmentOptions->GetWindowHeight())
268       {
269         // Environment options override full screen functionality if command line arguments not provided
270         mWindowPositionSize.width  = mEnvironmentOptions->GetWindowWidth();
271         mWindowPositionSize.height = mEnvironmentOptions->GetWindowHeight();
272       }
273     }
274
275     auto windowClassName = mEnvironmentOptions->GetWindowClassName();
276     auto windowName      = mEnvironmentOptions->GetWindowName();
277     if(!windowName.empty())
278     {
279       mMainWindowName = windowName;
280     }
281
282     windowData.SetPositionSize(mWindowPositionSize);
283     window = Internal::Adaptor::Window::New(mMainWindowName, windowClassName, windowData);
284   }
285   else
286   {
287     // The position, size and the window name of the pre-initialized application will be updated in ChangePreInitializedWindowInfo()
288     // when the real application is launched.
289     windowData.SetPositionSize(mWindowPositionSize);
290     window = Internal::Adaptor::Window::New("", "", windowData);
291   }
292
293   mMainWindow = Dali::Window(window);
294
295   // Quit the application when the window is closed
296   GetImplementation(mMainWindow).DeleteRequestSignal().Connect(mSlotDelegate, &Application::Quit);
297 }
298
299 void Application::CreateAdaptor()
300 {
301   DALI_ASSERT_ALWAYS(mMainWindow && "Window required to create adaptor");
302
303   auto graphicsFactory = mAdaptorBuilder->GetGraphicsFactory();
304
305   Integration::SceneHolder sceneHolder = Integration::SceneHolder(&Dali::GetImplementation(mMainWindow));
306
307   mAdaptor = Adaptor::New(graphicsFactory, sceneHolder, mEnvironmentOptions.get());
308
309   Adaptor::GetImplementation(*mAdaptor).SetUseRemoteSurface(mUseRemoteSurface);
310 }
311
312 void Application::CreateAdaptorBuilder()
313 {
314   mAdaptorBuilder = new AdaptorBuilder(*mEnvironmentOptions);
315 }
316
317 void Application::MainLoop()
318 {
319   // Run the application
320   mFramework->Run();
321 }
322
323 void Application::Lower()
324 {
325   // Lower the application without quitting it.
326   mMainWindow.Lower();
327 }
328
329 void Application::Quit()
330 {
331   // Actually quit the application.
332   // Force a call to Quit even if adaptor is not running.
333   Internal::Adaptor::Adaptor::GetImplementation(*mAdaptor).AddIdle(MakeCallback(this, &Application::QuitFromMainLoop), false, true);
334 }
335
336 void Application::QuitFromMainLoop()
337 {
338   Accessibility::Bridge::GetCurrentBridge()->Terminate();
339
340   mAdaptor->Stop();
341
342   mFramework->Quit();
343   // This will trigger OnTerminate(), below, after the main loop has completed.
344 }
345
346 void Application::OnInit()
347 {
348   mEnvironmentOptions = std::unique_ptr<EnvironmentOptions>(new EnvironmentOptions());
349
350   mFramework->AddAbortCallback(MakeCallback(this, &Application::QuitFromMainLoop));
351
352   CreateAdaptorBuilder();
353   // If an application was pre-initialized, a window was made in advance
354   if(mLaunchpadState == Launchpad::NONE)
355   {
356     DALI_LOG_RELEASE_INFO("default Window is created in standalone");
357     CreateWindow();
358   }
359
360   CreateAdaptor();
361
362   if(mLaunchpadState == Launchpad::PRE_INITIALIZED)
363   {
364     ChangePreInitializedWindowInfo();
365   }
366
367   // Run the adaptor
368   DALI_TRACE_BEGIN(gTraceFilter, "DALI_APP_ADAPTOR_START");
369   mAdaptor->Start();
370   DALI_TRACE_END(gTraceFilter, "DALI_APP_ADAPTOR_START");
371   Accessibility::Accessible::SetObjectRegistry(mAdaptor->GetObjectRegistry());
372
373   if(!mStylesheet.empty())
374   {
375     Dali::StyleMonitor::Get().SetTheme(mStylesheet);
376   }
377
378   // Wire up the LifecycleController
379   Dali::LifecycleController lifecycleController = Dali::LifecycleController::Get();
380
381   InitSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnInit);
382   TerminateSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnTerminate);
383   PauseSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnPause);
384   ResumeSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnResume);
385   ResetSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnReset);
386   LanguageChangedSignal().Connect(&GetImplementation(lifecycleController), &LifecycleController::OnLanguageChanged);
387
388   Dali::Application application(this);
389
390   DALI_TRACE_BEGIN(gTraceFilter, "DALI_APP_EMIT_INIT_SIGNAL");
391   mInitSignal.Emit(application);
392   DALI_TRACE_END(gTraceFilter, "DALI_APP_EMIT_INIT_SIGNAL");
393
394   mAdaptor->NotifySceneCreated();
395
396   // Ensure the join of Font thread at this point
397   Dali::TextAbstraction::FontClientJoinFontThreads();
398 }
399
400 void Application::OnTerminate()
401 {
402   // We've been told to quit by AppCore, ecore_x_destroy has been called, need to quit synchronously
403   // delete the window as ecore_x has been destroyed by AppCore
404
405   Dali::Application application(this);
406   mTerminateSignal.Emit(application);
407
408   if(mAdaptor)
409   {
410     // Ensure that the render-thread is not using the surface(window) after we delete it
411     mAdaptor->Stop();
412   }
413
414   mMainWindow.Reset(); // This only resets (clears) the default Window
415
416   // If DALi's UI Thread works, some resources are created in UI Thread, not Main thread.
417   // For that case, these resource should be deleted in UI Thread.
418   if(mUseUiThread)
419   {
420     delete mAdaptor;
421     delete mAdaptorBuilder;
422     WindowSystem::Shutdown();
423   }
424 }
425
426 void Application::OnPause()
427 {
428   // A DALi app should handle Pause/Resume events.
429   // DALi just delivers the framework Pause event to the application, but not actually pause DALi core.
430   // Pausing DALi core only occurs on the Window Hidden framework event
431   Dali::Application application(this);
432   mPauseSignal.Emit(application);
433 }
434
435 void Application::OnResume()
436 {
437   // Emit the signal first so the application can queue any messages before we do an update/render
438   // This ensures we do not just redraw the last frame before pausing if that's not required
439   Dali::Application application(this);
440   mResumeSignal.Emit(application);
441
442   // DALi just delivers the framework Resume event to the application.
443   // Resuming DALi core only occurs on the Window Show framework event
444
445   // Trigger processing of events queued up while paused
446   CoreEventInterface& coreEventInterface = Internal::Adaptor::Adaptor::GetImplementation(GetAdaptor());
447   coreEventInterface.ProcessCoreEvents();
448 }
449
450 void Application::OnReset()
451 {
452   /*
453    * usually, reset callback was called when a caller request to launch this application via aul.
454    * because Application class already handled initialization in OnInit(), OnReset do nothing.
455    */
456   Dali::Application application(this);
457   mResetSignal.Emit(application);
458 }
459
460 void Application::OnAppControl(void* data)
461 {
462   Dali::Application application(this);
463   mAppControlSignal.Emit(application, data);
464 }
465
466 void Application::OnLanguageChanged()
467 {
468   mAdaptor->NotifyLanguageChanged();
469   Dali::Application application(this);
470   mLanguageChangedSignal.Emit(application);
471 }
472
473 void Application::OnRegionChanged()
474 {
475   Dali::Application application(this);
476   mRegionChangedSignal.Emit(application);
477 }
478
479 void Application::OnBatteryLow(Dali::DeviceStatus::Battery::Status status)
480 {
481   Dali::Application application(this);
482   mLowBatterySignal.Emit(status);
483 }
484
485 void Application::OnMemoryLow(Dali::DeviceStatus::Memory::Status status)
486 {
487   Dali::Application application(this);
488   mLowMemorySignal.Emit(status);
489 }
490
491 void Application::OnDeviceOrientationChanged(Dali::DeviceStatus::Orientation::Status status)
492 {
493   Dali::Application application(this);
494   mDeviceOrientationChangedSignal.Emit(status);
495 }
496
497 void Application::OnSurfaceCreated(Any newSurface)
498 {
499   void* newWindow = AnyCast<void*>(newSurface);
500   void* oldWindow = AnyCast<void*>(mMainWindow.GetNativeHandle());
501   if(oldWindow != newWindow)
502   {
503     auto                                 renderSurfaceFactory = Dali::Internal::Adaptor::GetRenderSurfaceFactory();
504     std::unique_ptr<WindowRenderSurface> newSurfacePtr        = renderSurfaceFactory->CreateWindowRenderSurface(PositionSize(), newSurface, true);
505
506     mAdaptor->ReplaceSurface(mMainWindow, *newSurfacePtr.release());
507   }
508 }
509
510 void Application::OnSurfaceDestroyed(Any surface)
511 {
512 }
513
514 void Application::OnTaskInit()
515 {
516   Dali::Application application(this);
517   mTaskInitSignal.Emit(application);
518 }
519
520 void Application::OnTaskTerminate()
521 {
522   Dali::Application application(this);
523   mTaskTerminateSignal.Emit(application);
524 }
525
526 void Application::OnTaskAppControl(void* data)
527 {
528   Dali::Application application(this);
529   mTaskAppControlSignal.Emit(application, data);
530 }
531
532 void Application::OnTaskLanguageChanged()
533 {
534   Dali::Application application(this);
535   mTaskLanguageChangedSignal.Emit(application);
536 }
537
538 void Application::OnTaskRegionChanged()
539 {
540   Dali::Application application(this);
541   mTaskRegionChangedSignal.Emit(application);
542 }
543
544 void Application::OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status)
545 {
546   Dali::Application application(this);
547   mTaskLowBatterySignal.Emit(status);
548 }
549
550 void Application::OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status)
551 {
552   Dali::Application application(this);
553   mTaskLowMemorySignal.Emit(status);
554 }
555
556 void Application::OnTaskDeviceOrientationChanged(Dali::DeviceStatus::Orientation::Status status)
557 {
558   Dali::Application application(this);
559   mTaskDeviceOrientationChangedSignal.Emit(status);
560 }
561
562 bool Application::AddIdle(CallbackBase* callback, bool hasReturnValue)
563 {
564   return mAdaptor->AddIdle(callback, hasReturnValue);
565 }
566
567 std::string Application::GetRegion() const
568 {
569   return mFramework->GetRegion();
570 }
571
572 std::string Application::GetLanguage() const
573 {
574   return mFramework->GetLanguage();
575 }
576
577 Dali::ObjectRegistry Application::GetObjectRegistry() const
578 {
579   Dali::ObjectRegistry objectRegistry;
580   if(mAdaptor)
581   {
582     objectRegistry = mAdaptor->GetObjectRegistry();
583   }
584   return objectRegistry;
585 }
586
587 Dali::Adaptor& Application::GetAdaptor()
588 {
589   return *mAdaptor;
590 }
591
592 Dali::Window Application::GetWindow()
593 {
594   return mMainWindow;
595 }
596
597 std::string Application::GetResourcePath()
598 {
599   return SystemSettings::GetResourcePath();
600 }
601
602 std::string Application::GetDataPath()
603 {
604   return SystemSettings::GetDataPath();
605 }
606
607 void Application::SetStyleSheet(const std::string& stylesheet)
608 {
609   mStylesheet = stylesheet;
610 }
611
612 void Application::SetCommandLineOptions(int* argc, char** argv[])
613 {
614   delete mCommandLineOptions;
615
616   mCommandLineOptions = new CommandLineOptions(argc, argv);
617
618   mFramework->SetCommandLineOptions(argc, argv);
619
620   if(argc && (*argc > 0))
621   {
622     // Set mName from command-line args
623     mMainWindowName = (*argv)[0];
624   }
625 }
626
627 void Application::SetDefaultWindowType(WindowType type)
628 {
629   mDefaultWindowType = type;
630   mMainWindow.SetType(type);
631 }
632
633 int32_t Application::GetRenderThreadId() const
634 {
635   if(mAdaptor)
636   {
637     return Internal::Adaptor::Adaptor::GetImplementation(*mAdaptor).GetRenderThreadId();
638   }
639   return 0;
640 }
641
642 ApplicationPtr Application::GetPreInitializedApplication()
643 {
644   // Reset the handle to decrease the reference count
645   ApplicationPtr application = gPreInitializedApplication;
646   gPreInitializedApplication.Reset();
647
648   return application;
649 }
650
651 } // namespace Adaptor
652
653 } // namespace Internal
654
655 } // namespace Dali