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