8e38ca54e0397ad31b9dd0866748738477f3df92
[platform/core/uifw/dali-adaptor.git] / dali / internal / adaptor / common / application-impl.cpp
1 /*
2  * Copyright (c) 2020 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/integration-api/debug.h>
23 #include <dali/devel-api/common/singleton-service.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/devel-api/adaptor-framework/style-monitor.h>
27 #include <dali/devel-api/text-abstraction/font-client.h>
28 #include <dali/internal/adaptor/common/adaptor-impl.h>
29 #include <dali/internal/system/common/command-line-options.h>
30 #include <dali/internal/adaptor/common/framework.h>
31 #include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
32 #include <dali/internal/window-system/common/window-impl.h>
33 #include <dali/internal/window-system/common/window-render-surface.h>
34 #include <dali/internal/window-system/common/render-surface-factory.h>
35
36 // To disable a macro with the same name from one of OpenGL headers
37 #undef Status
38
39 namespace Dali
40 {
41
42 namespace TizenPlatform
43 {
44 class TizenPlatformAbstraction;
45 }
46
47 namespace Integration
48 {
49 class Core;
50 }
51
52 namespace Internal
53 {
54
55 namespace Adaptor
56 {
57
58 namespace
59 {
60
61 const float DEFAULT_STEREO_BASE( 65.0f );
62
63 } // unnamed namespace
64
65 ApplicationPtr Application::gPreInitializedApplication( NULL );
66
67 ApplicationPtr Application::New(
68   int* argc,
69   char **argv[],
70   const std::string& stylesheet,
71   Dali::Application::WINDOW_MODE windowMode,
72   const PositionSize& positionSize,
73   Framework::Type applicationType)
74 {
75   ApplicationPtr application ( new Application (argc, argv, stylesheet, windowMode, positionSize, applicationType ) );
76   return application;
77 }
78
79 void Application::PreInitialize( int* argc, char** argv[] )
80 {
81   if( !gPreInitializedApplication )
82   {
83     gPreInitializedApplication = new Application ( argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL );
84     gPreInitializedApplication->CreateWindow();    // Only create window
85     gPreInitializedApplication->mLaunchpadState = Launchpad::PRE_INITIALIZED;
86   }
87 }
88
89 Application::Application( int* argc, char** argv[], const std::string& stylesheet,
90   Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType )
91 : mInitSignal(),
92   mTerminateSignal(),
93   mPauseSignal(),
94   mResumeSignal(),
95   mResetSignal(),
96   mResizeSignal(),
97   mAppControlSignal(),
98   mLanguageChangedSignal(),
99   mRegionChangedSignal(),
100   mBatteryLowSignal(),
101   mMemoryLowSignal(),
102   mEventLoop( nullptr ),
103   mFramework( nullptr ),
104   mContextLossConfiguration( Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS ),
105   mCommandLineOptions( nullptr ),
106   mAdaptorBuilder( nullptr ),
107   mAdaptor( nullptr ),
108   mMainWindow(),
109   mMainWindowMode( windowMode ),
110   mMainWindowName(),
111   mMainWindowReplaced( false ),
112   mStylesheet( stylesheet ),
113   mEnvironmentOptions(),
114   mWindowPositionSize( positionSize ),
115   mLaunchpadState( Launchpad::NONE ),
116   mSlotDelegate( this ),
117   mViewMode( MONO ),
118   mStereoBase( DEFAULT_STEREO_BASE )
119 {
120   // Get mName from environment options
121   mMainWindowName = mEnvironmentOptions.GetWindowName();
122   if( mMainWindowName.empty() && argc && ( *argc > 0 ) )
123   {
124     // Set mName from command-line args if environment option not set
125     mMainWindowName = (*argv)[0];
126   }
127
128   mCommandLineOptions = new CommandLineOptions(argc, argv);
129   mFramework = new Framework( *this, argc, argv, applicationType );
130   mUseRemoteSurface = (applicationType == Framework::WATCH);
131 }
132
133 Application::~Application()
134 {
135   SingletonService service = SingletonService::Get();
136   // Note this can be false i.e. if Application has never created a Core instance
137   if( service )
138   {
139     service.UnregisterAll();
140   }
141
142   mMainWindow.Reset();
143   delete mAdaptor;
144   delete mAdaptorBuilder;
145   delete mCommandLineOptions;
146   delete mFramework;
147 }
148
149 void Application::CreateWindow()
150 {
151   if( mWindowPositionSize.width == 0 && mWindowPositionSize.height == 0 )
152   {
153     if( mCommandLineOptions->stageWidth > 0 && mCommandLineOptions->stageHeight > 0 )
154     {
155       // Command line options override environment options and full screen
156       mWindowPositionSize.width = mCommandLineOptions->stageWidth;
157       mWindowPositionSize.height = mCommandLineOptions->stageHeight;
158     }
159     else if( mEnvironmentOptions.GetWindowWidth() && mEnvironmentOptions.GetWindowHeight() )
160     {
161       // Environment options override full screen functionality if command line arguments not provided
162       mWindowPositionSize.width = mEnvironmentOptions.GetWindowWidth();
163       mWindowPositionSize.height = mEnvironmentOptions.GetWindowHeight();
164     }
165   }
166
167   const std::string& windowClassName = mEnvironmentOptions.GetWindowClassName();
168
169   Internal::Adaptor::Window* window = Internal::Adaptor::Window::New( mWindowPositionSize, mMainWindowName, windowClassName, mMainWindowMode == Dali::Application::TRANSPARENT );
170   mMainWindow = Dali::Window( window );
171
172   // Quit the application when the window is closed
173   GetImplementation( mMainWindow ).DeleteRequestSignal().Connect( mSlotDelegate, &Application::Quit );
174 }
175
176 void Application::CreateAdaptor()
177 {
178   DALI_ASSERT_ALWAYS( mMainWindow && "Window required to create adaptor" );
179
180   auto graphicsFactory = mAdaptorBuilder->GetGraphicsFactory();
181
182   Integration::SceneHolder sceneHolder = Integration::SceneHolder( &Dali::GetImplementation( mMainWindow ) );
183
184   mAdaptor = Adaptor::New( graphicsFactory, sceneHolder, mContextLossConfiguration, &mEnvironmentOptions );
185
186   mAdaptor->ResizedSignal().Connect( mSlotDelegate, &Application::OnResize );
187
188   Adaptor::GetImplementation( *mAdaptor ).SetUseRemoteSurface( mUseRemoteSurface );
189 }
190
191 void Application::CreateAdaptorBuilder()
192 {
193   mAdaptorBuilder = new AdaptorBuilder();
194 }
195
196 void Application::MainLoop(Dali::Configuration::ContextLoss configuration)
197 {
198   mContextLossConfiguration = configuration;
199
200   // Run the application
201   mFramework->Run();
202 }
203
204 void Application::Lower()
205 {
206   // Lower the application without quitting it.
207   mMainWindow.Lower();
208 }
209
210 void Application::Quit()
211 {
212   // Actually quit the application.
213   // Force a call to Quit even if adaptor is not running.
214   Internal::Adaptor::Adaptor::GetImplementation(*mAdaptor).AddIdle( MakeCallback( this, &Application::QuitFromMainLoop ), false, true );
215 }
216
217 void Application::QuitFromMainLoop()
218 {
219   mAdaptor->Stop();
220
221   mFramework->Quit();
222   // This will trigger OnTerminate(), below, after the main loop has completed.
223 }
224
225 void Application::OnInit()
226 {
227   mFramework->AddAbortCallback( MakeCallback( this, &Application::QuitFromMainLoop ) );
228
229   CreateAdaptorBuilder();
230   // If an application was pre-initialized, a window was made in advance
231   if( mLaunchpadState == Launchpad::NONE )
232   {
233     CreateWindow();
234   }
235
236   CreateAdaptor();
237
238   // Run the adaptor
239   mAdaptor->Start();
240
241   if( ! mStylesheet.empty() )
242   {
243     Dali::StyleMonitor::Get().SetTheme( mStylesheet );
244   }
245
246   // Wire up the LifecycleController
247   Dali::LifecycleController lifecycleController = Dali::LifecycleController::Get();
248
249   InitSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnInit );
250   TerminateSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnTerminate );
251   PauseSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnPause );
252   ResumeSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnResume );
253   ResetSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnReset );
254   ResizeSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnResize );
255   LanguageChangedSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnLanguageChanged );
256
257   Dali::Application application(this);
258   mInitSignal.Emit( application );
259
260   mAdaptor->NotifySceneCreated();
261 }
262
263 void Application::OnTerminate()
264 {
265   // We've been told to quit by AppCore, ecore_x_destroy has been called, need to quit synchronously
266   // delete the window as ecore_x has been destroyed by AppCore
267
268   Dali::Application application(this);
269   mTerminateSignal.Emit( application );
270
271   if( mAdaptor )
272   {
273     // Ensure that the render-thread is not using the surface(window) after we delete it
274     mAdaptor->Stop();
275   }
276
277   mMainWindow.Reset(); // This only resets (clears) the default Window
278 }
279
280 void Application::OnPause()
281 {
282   // A DALi app should handle Pause/Resume events.
283   // DALi just delivers the framework Pause event to the application, but not actually pause DALi core.
284   // Pausing DALi core only occurs on the Window Hidden framework event
285   Dali::Application application(this);
286   mPauseSignal.Emit( application );
287 }
288
289 void Application::OnResume()
290 {
291   // Emit the signal first so the application can queue any messages before we do an update/render
292   // This ensures we do not just redraw the last frame before pausing if that's not required
293   Dali::Application application(this);
294   mResumeSignal.Emit( application );
295
296   // DALi just delivers the framework Resume event to the application.
297   // Resuming DALi core only occurs on the Window Show framework event
298
299   // Trigger processing of events queued up while paused
300   CoreEventInterface& coreEventInterface = Internal::Adaptor::Adaptor::GetImplementation( GetAdaptor() );
301   coreEventInterface.ProcessCoreEvents();
302 }
303
304 void Application::OnReset()
305 {
306   /*
307    * usually, reset callback was called when a caller request to launch this application via aul.
308    * because Application class already handled initialization in OnInit(), OnReset do nothing.
309    */
310   Dali::Application application(this);
311   mResetSignal.Emit( application );
312 }
313
314 void Application::OnAppControl(void *data)
315 {
316   Dali::Application application(this);
317   mAppControlSignal.Emit( application , data );
318 }
319
320 void Application::OnLanguageChanged()
321 {
322   mAdaptor->NotifyLanguageChanged();
323   Dali::Application application(this);
324   mLanguageChangedSignal.Emit( application );
325 }
326
327 void Application::OnRegionChanged()
328 {
329   Dali::Application application(this);
330   mRegionChangedSignal.Emit( application );
331 }
332
333 void Application::OnBatteryLow( Dali::DeviceStatus::Battery::Status status )
334 {
335   Dali::Application application(this);
336   mBatteryLowSignal.Emit( application );
337
338   mLowBatterySignal.Emit( status );
339 }
340
341 void Application::OnMemoryLow( Dali::DeviceStatus::Memory::Status status )
342 {
343   Dali::Application application(this);
344   mMemoryLowSignal.Emit( application );
345
346   mLowMemorySignal.Emit( status );
347 }
348
349 void Application::OnSurfaceCreated( Any newSurface )
350 {
351   void* newWindow = AnyCast< void* >( newSurface );
352   void* oldWindow = AnyCast< void* >( mMainWindow.GetNativeHandle() );
353   if( oldWindow != newWindow )
354   {
355     auto renderSurfaceFactory = Dali::Internal::Adaptor::GetRenderSurfaceFactory();
356     std::unique_ptr< WindowRenderSurface > newSurfacePtr
357       = renderSurfaceFactory->CreateWindowRenderSurface( PositionSize(), newSurface, true );
358
359     mAdaptor->ReplaceSurface( mMainWindow, *newSurfacePtr.release() );
360   }
361 }
362
363 void Application::OnSurfaceDestroyed( Any surface )
364 {
365 }
366
367 void Application::OnResize(Dali::Adaptor& adaptor)
368 {
369   Dali::Application application(this);
370   mResizeSignal.Emit( application );
371 }
372
373 bool Application::AddIdle( CallbackBase* callback, bool hasReturnValue )
374 {
375   return mAdaptor->AddIdle( callback, hasReturnValue );
376 }
377
378 std::string Application::GetRegion() const
379 {
380   return mFramework->GetRegion();
381 }
382
383 std::string Application::GetLanguage() const
384 {
385   return mFramework->GetLanguage();
386 }
387
388 Dali::Adaptor& Application::GetAdaptor()
389 {
390   return *mAdaptor;
391 }
392
393 Dali::Window Application::GetWindow()
394 {
395   // Changed to return a different window handle after ReplaceWindow is called
396   // just for backward compatibility to make the test case pass
397   if ( mMainWindowReplaced )
398   {
399     Internal::Adaptor::Window* window = Internal::Adaptor::Window::New( PositionSize(), "ReplacedWindow", "", false );
400     return Dali::Window( window );
401   }
402   else
403   {
404     return mMainWindow;
405   }
406 }
407
408 // Stereoscopy
409
410 void Application::SetViewMode( ViewMode viewMode )
411 {
412   mViewMode = viewMode;
413 }
414
415 ViewMode Application::GetViewMode() const
416 {
417   return mViewMode;
418 }
419
420 void Application::SetStereoBase( float stereoBase )
421 {
422   mStereoBase = stereoBase;
423 }
424
425 float Application::GetStereoBase() const
426 {
427   return mStereoBase;
428 }
429
430 void Application::ReplaceWindow( const PositionSize& positionSize, const std::string& name )
431 {
432   // This API is kept just for backward compatibility to make the test case pass.
433
434   mMainWindowReplaced = true;
435   OnResize( *mAdaptor );
436 }
437
438 std::string Application::GetResourcePath()
439 {
440   return Internal::Adaptor::Framework::GetResourcePath();
441 }
442
443 std::string Application::GetDataPath()
444 {
445   return Internal::Adaptor::Framework::GetDataPath();
446 }
447
448 void Application::SetStyleSheet( const std::string& stylesheet )
449 {
450   mStylesheet = stylesheet;
451 }
452
453 void Application::SetCommandLineOptions( int* argc, char **argv[] )
454 {
455   delete mCommandLineOptions;
456
457   mCommandLineOptions = new CommandLineOptions( argc, argv );
458
459   mFramework->SetCommandLineOptions( argc, argv );
460 }
461
462 ApplicationPtr Application::GetPreInitializedApplication()
463 {
464   return gPreInitializedApplication;
465 }
466
467 } // namespace Adaptor
468
469 } // namespace Internal
470
471 } // namespace Dali