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