The UiThread means that the application creates a thread for the UI events.
So the Dali::Adaptor is created on the UiThread, not the main thread.
When you enable UiThread,
the signals (Init, Terminate, Pause, Resume, Reset, AppControl, LanguageChanged, RegionChanged, LowBattery, LowMemory)
are emitted on the UiThread.
If you want to get the events on the main thread, you must connect the task signals(TaskInit, TaskTerminate, etc.).
When you don't enable the UiThread, the task signals aren't emitted.
Change-Id: I2cc57e85fa50f9b854531efa6048796aadbe6da9
internal->StoreWindowPositionSize(positionSize);
} else
{
- internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, type);
+ internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, type, false);
}
return Application(internal.Get());
}
}
};
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
: mObserver(observer),
+ mTaskObserver(taskObserver),
mInitialised(false),
mPaused(false),
mRunning(false),
std::string mRegion;
};
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
: mObserver(observer),
+ mTaskObserver(taskObserver),
mInitialised(false),
mPaused(false),
mRunning(false),
// INTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/devel-api/adaptor-framework/style-monitor.h>
#include <dali/devel-api/atspi-interfaces/accessible.h>
#include <dali/devel-api/text-abstraction/font-client.h>
#include <dali/internal/adaptor/common/framework.h>
#include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
#include <dali/internal/system/common/command-line-options.h>
+#include <dali/internal/system/common/environment-variables.h>
#include <dali/internal/window-system/common/render-surface-factory.h>
#include <dali/internal/window-system/common/window-impl.h>
#include <dali/internal/window-system/common/window-render-surface.h>
Dali::Application::WINDOW_MODE windowMode,
const PositionSize& positionSize,
Framework::Type applicationType,
- WindowType type)
+ WindowType type,
+ bool useUiThread)
{
- ApplicationPtr application(new Application(argc, argv, stylesheet, windowMode, positionSize, applicationType, type));
+ ApplicationPtr application(new Application(argc, argv, stylesheet, windowMode, positionSize, applicationType, type, useUiThread));
return application;
}
{
Dali::TextAbstraction::FontClientPreInitialize();
- gPreInitializedApplication = new Application(argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL, WindowType::NORMAL);
+ gPreInitializedApplication = new Application(argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL, WindowType::NORMAL, false);
gPreInitializedApplication->CreateWindow(); // Only create window
gPreInitializedApplication->mLaunchpadState = Launchpad::PRE_INITIALIZED;
}
}
-Application::Application(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type)
+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)
: mInitSignal(),
mTerminateSignal(),
mPauseSignal(),
mWindowPositionSize(positionSize),
mLaunchpadState(Launchpad::NONE),
mDefaultWindowType(type),
+ mUseUiThread(useUiThread),
mSlotDelegate(this)
{
// Get mName from environment options
mMainWindowName = (*argv)[0];
}
+ const char* uiThreadEnabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_ENABLE_UI_THREAD);
+ if(uiThreadEnabled && std::atoi(uiThreadEnabled) != 0)
+ {
+ mUseUiThread = true;
+ }
+
mCommandLineOptions = new CommandLineOptions(argc, argv);
- mFramework = new Framework(*this, argc, argv, applicationType);
+ mFramework = new Framework(*this, *this, argc, argv, applicationType, mUseUiThread);
mUseRemoteSurface = (applicationType == Framework::WATCH);
}
}
else if(screenWidth != mWindowPositionSize.width || screenHeight != mWindowPositionSize.height)
{
- //Some apps can receive screen size differently after launching by specifying size in manifest.
+ // Some apps can receive screen size differently after launching by specifying size in manifest.
mWindowPositionSize.width = screenWidth;
mWindowPositionSize.height = screenHeight;
mMainWindow.SetSize(Dali::Window::WindowSize(mWindowPositionSize.width, mWindowPositionSize.height));
{
}
+void Application::OnTaskInit()
+{
+ Dali::Application application(this);
+ mTaskInitSignal.Emit(application);
+}
+
+void Application::OnTaskTerminate()
+{
+ Dali::Application application(this);
+ mTaskTerminateSignal.Emit(application);
+}
+
+void Application::OnTaskAppControl(void* data)
+{
+ Dali::Application application(this);
+ mTaskAppControlSignal.Emit(application, data);
+}
+
+void Application::OnTaskLanguageChanged()
+{
+ Dali::Application application(this);
+ mTaskLanguageChangedSignal.Emit(application);
+}
+
+void Application::OnTaskRegionChanged()
+{
+ Dali::Application application(this);
+ mTaskRegionChangedSignal.Emit(application);
+}
+
+void Application::OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status)
+{
+ Dali::Application application(this);
+ mTaskLowBatterySignal.Emit(status);
+}
+
+void Application::OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status)
+{
+ Dali::Application application(this);
+ mTaskLowMemorySignal.Emit(status);
+}
+
bool Application::AddIdle(CallbackBase* callback, bool hasReturnValue)
{
return mAdaptor->AddIdle(callback, hasReturnValue);
/**
* Implementation of the Application class.
*/
-class Application : public BaseObject, public Framework::Observer
+class Application : public BaseObject, public Framework::Observer, public Framework::TaskObserver
{
public:
typedef Dali::Application::LowBatterySignalType LowBatterySignalType;
* @param[in] positionSize A position and a size of the window
* @param[in] applicationType A member of Dali::Framework::Type
* @param[in] type It is window type for default window.
+ * @param[in] useUiThread True if the application would create a UI thread
*/
- static ApplicationPtr New(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type);
+ static ApplicationPtr New(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type, bool useUiThread);
/**
* @copydoc Dali::DevelApplication::PreInitialize()
void OnResume() override;
/**
- * Called when the framework received AppControlSignal.
- * @param[in] The bundle data of AppControl event.
- */
+ * Called when the framework received AppControlSignal.
+ * @param[in] The bundle data of AppControl event.
+ */
void OnAppControl(void* data) override;
/**
void OnLanguageChanged() override;
/**
- * Called when the framework informs the application that the region of the device has changed.
- */
+ * Called when the framework informs the application that the region of the device has changed.
+ */
void OnRegionChanged() override;
/**
- * Called when the framework informs the application that the battery level of the device is low.
- */
+ * Called when the framework informs the application that the battery level of the device is low.
+ */
void OnBatteryLow(Dali::DeviceStatus::Battery::Status status) override;
/**
- * Called when the framework informs the application that the memory level of the device is low.
- */
+ * Called when the framework informs the application that the memory level of the device is low.
+ */
void OnMemoryLow(Dali::DeviceStatus::Memory::Status status) override;
/**
*/
void OnSurfaceDestroyed(Any newSurface) override;
+public: // From Framework::TaskObserver
+ /**
+ * Called when the framework is initialised.
+ */
+ void OnTaskInit() override;
+
+ /**
+ * Called when the framework is terminated.
+ */
+ void OnTaskTerminate() override;
+
+ /**
+ * Called when the framework received AppControlSignal.
+ * @param[in] The bundle data of AppControl event.
+ */
+ void OnTaskAppControl(void* data) override;
+
+ /**
+ * Called when the framework informs the application that the language of the device has changed.
+ */
+ void OnTaskLanguageChanged() override;
+
+ /**
+ * Called when the framework informs the application that the region of the device has changed.
+ */
+ void OnTaskRegionChanged() override;
+
+ /**
+ * Called when the framework informs the application that the battery level of the device is low.
+ */
+ void OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status) override;
+
+ /**
+ * Called when the framework informs the application that the memory level of the device is low.
+ */
+ void OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status) override;
+
public:
/**
* Sets a user defined theme file.
}
/**
- * @copydoc Dali::Application::AppControlSignal()
- */
+ * @copydoc Dali::Application::AppControlSignal()
+ */
Dali::Application::AppControlSignalType& AppControlSignal()
{
return mAppControlSignal;
}
/**
- * @copydoc Dali::Application::RegionChangedSignal()
- */
+ * @copydoc Dali::Application::RegionChangedSignal()
+ */
Dali::Application::AppSignalType& RegionChangedSignal()
{
return mRegionChangedSignal;
}
/**
- * @copydoc Dali::Application::LowBatterySignal()
- */
+ * @copydoc Dali::Application::LowBatterySignal()
+ */
Dali::Application::LowBatterySignalType& LowBatterySignal()
{
return mLowBatterySignal;
}
/**
- * @copydoc Dali::Application:::LowMemorySignal()
- */
+ * @copydoc Dali::Application:::LowMemorySignal()
+ */
Dali::Application::LowMemorySignalType& LowMemorySignal()
{
return mLowMemorySignal;
}
+ /**
+ * @copydoc Dali::Application::TaskInitSignal()
+ */
+ Dali::Application::AppSignalType& TaskInitSignal()
+ {
+ return mTaskInitSignal;
+ }
+
+ /**
+ * @copydoc Dali::Application::TaskTerminateSignal()
+ */
+ Dali::Application::AppSignalType& TaskTerminateSignal()
+ {
+ return mTaskTerminateSignal;
+ }
+
+ /**
+ * @copydoc Dali::Application::TaskAppControlSignal()
+ */
+ Dali::Application::AppControlSignalType& TaskAppControlSignal()
+ {
+ return mTaskAppControlSignal;
+ }
+
+ /**
+ * @copydoc Dali::Application::TaskLanguageChangedSignal()
+ */
+ Dali::Application::AppSignalType& TaskLanguageChangedSignal()
+ {
+ return mTaskLanguageChangedSignal;
+ }
+
+ /**
+ * @copydoc Dali::Application::TaskRegionChangedSignal()
+ */
+ Dali::Application::AppSignalType& TaskRegionChangedSignal()
+ {
+ return mTaskRegionChangedSignal;
+ }
+
+ /**
+ * @copydoc Dali::Application::TaskLowBatterySignal()
+ */
+ Dali::Application::LowBatterySignalType& TaskLowBatterySignal()
+ {
+ return mTaskLowBatterySignal;
+ }
+
+ /**
+ * @copydoc Dali::Application::TaskLowMemorySignal()
+ */
+ Dali::Application::LowMemorySignalType& TaskLowMemorySignal()
+ {
+ return mTaskLowMemorySignal;
+ }
+
protected:
/**
* Private Constructor
* @param[in] positionSize A position and a size of the window
* @param[in] applicationType A member of Dali::Framework::Type
* @param[in] type The default window's type.
+ * @param[in] useUiThread True if the application would create UI thread
*/
- Application(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type);
+ Application(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type, bool useUiThread);
/**
* Destructor
LowBatterySignalType mLowBatterySignal;
LowMemorySignalType mLowMemorySignal;
+ AppSignalType mTaskInitSignal;
+ AppSignalType mTaskTerminateSignal;
+ AppControlSignalType mTaskAppControlSignal;
+ AppSignalType mTaskLanguageChangedSignal;
+ AppSignalType mTaskRegionChangedSignal;
+ LowBatterySignalType mTaskLowBatterySignal;
+ LowMemorySignalType mTaskLowMemorySignal;
+
EventLoop* mEventLoop;
Framework* mFramework;
Launchpad::State mLaunchpadState;
bool mUseRemoteSurface;
WindowType mDefaultWindowType; ///< Default window's type. It is used when Application is created.
+ bool mUseUiThread;
SlotDelegate<Application> mSlotDelegate;
/**
* Observer class for the framework.
+ * @brief When the UI thread is enabled, the events are emitted on the UI thread.
+ * When it is disabled, the events are emitted on the main thread.
*/
class Observer
{
}
/**
- * Invoked when the AppControl message is received.
- * @param[in] The bundle data of AppControl message.
- */
+ * Invoked when the AppControl message is received.
+ * @param[in] The bundle data of AppControl message.
+ */
virtual void OnAppControl(void*)
{
}
#endif
};
+ /**
+ * TaskObserver class for the framework.
+ * @brief This is used only when UiThread is enabled. the events are emitted on the main thread.
+ */
+ class TaskObserver
+ {
+ public:
+ /**
+ * Invoked when the application is to be initialised.
+ */
+ virtual void OnTaskInit()
+ {
+ }
+
+ /**
+ * Invoked when the application is to be terminated.
+ */
+ virtual void OnTaskTerminate()
+ {
+ }
+
+ /**
+ * Invoked when the AppControl message is received.
+ * @param[in] The bundle data of AppControl message.
+ */
+ virtual void OnTaskAppControl(void*)
+ {
+ }
+
+ /**
+ * Invoked when the language of the device is changed.
+ */
+ virtual void OnTaskLanguageChanged()
+ {
+ }
+
+ /**
+ * Invoked when the region is changed.
+ */
+ virtual void OnTaskRegionChanged()
+ {
+ }
+
+ /**
+ * Invoked when the battery level of the device is low.
+ */
+ virtual void OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status)
+ {
+ }
+
+ /**
+ * Invoked when the memory level of the device is low.
+ */
+ virtual void OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status)
+ {
+ }
+ };
+
public:
/**
* Constructor
- * @param[in] observer The observer of the Framework.
- * @param[in] argc A pointer to the number of arguments.
- * @param[in] argv A pointer the the argument list.
- * @param[in] type The type of application
+ * @param[in] observer The observer of the Framework.
+ * @param[in] taskObserver The task observer of the Framework.
+ * @param[in] argc A pointer to the number of arguments.
+ * @param[in] argv A pointer the the argument list.
+ * @param[in] type The type of application
+ * @param[in] useUiThread True if the application would create a UI thread
*/
- Framework(Observer& observer, int* argc, char*** argv, Type type = NORMAL);
+ Framework(Observer& observer, TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread);
/**
* Destructor
void InitThreads();
private:
- Observer& mObserver;
- bool mInitialised;
- bool mPaused;
- bool mRunning;
- int* mArgc;
- char*** mArgv;
- std::string mBundleName;
- std::string mBundleId;
- AbortHandler mAbortHandler;
+ Observer& mObserver;
+ TaskObserver& mTaskObserver;
+ bool mInitialised;
+ bool mPaused;
+ bool mRunning;
+ int* mArgc;
+ char*** mArgv;
+ std::string mBundleName;
+ std::string mBundleId;
+ AbortHandler mAbortHandler;
private: // impl members
struct Impl;
std::string mRegion;
};
-Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
: mObserver(observer),
+ mTaskObserver(taskObserver),
mInitialised(false),
mPaused(false),
mRunning(false),
}
ComponentApplication::ComponentApplication(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode)
-: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::COMPONENT, WindowType::NORMAL)
+: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::COMPONENT, WindowType::NORMAL, false)
{
}
#include <app_control_internal.h>
#include <bundle.h>
#include <bundle_internal.h>
+#include <dlog.h>
+#include <glib.h>
#include <system_info.h>
#include <system_settings.h>
#include <widget_base.h>
#include <app_core_ui_base.hh>
#include <app_event_internal.hh>
+
// CONDITIONAL INCLUDES
#ifdef APPCORE_WATCH_AVAILABLE
#include <appcore-watch/watch_app.h>
class UiAppContext : public AppCoreUiBase
{
public:
+ class Task : public AppCoreTaskBase
+ {
+ public:
+ explicit Task(Framework* framework)
+ : mFramework(framework),
+ mNewBatteryStatus(Dali::DeviceStatus::Battery::Status::NORMAL),
+ mNewMemoryStatus(Dali::DeviceStatus::Memory::NORMAL)
+ {
+ }
+
+ virtual ~Task()
+ {
+ }
+
+ int OnCreate() override
+ {
+ // On the main thread, the log functions are not set. So print_log() is used directly.
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnCreate() emitted", __MODULE__, __func__, __LINE__);
+ mFramework->mTaskObserver.OnTaskInit();
+ return AppCoreTaskBase::OnCreate();
+ }
+
+ int OnTerminate() override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnTerminate() emitted", __MODULE__, __func__, __LINE__);
+ mFramework->mTaskObserver.OnTaskTerminate();
+ return AppCoreTaskBase::OnTerminate();
+ }
+
+ int OnControl(tizen_base::Bundle b) override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnControl() emitted", __MODULE__, __func__, __LINE__);
+ AppCoreTaskBase::OnControl(b);
+
+ app_control_h appControl = nullptr;
+
+ auto* bundleData = b.GetHandle();
+ if(bundleData)
+ {
+ if(app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
+ {
+ print_log(DLOG_ERROR, "DALI", "%s: %s(%d) > Failed to create an app_control handle with Bundle", __MODULE__, __func__, __LINE__);
+ }
+ }
+ else
+ {
+ if(app_control_create(&appControl) != TIZEN_ERROR_NONE)
+ {
+ print_log(DLOG_ERROR, "DALI", "%s: %s(%d) > Failed to create an app_control handle", __MODULE__, __func__, __LINE__);
+ }
+ }
+ mFramework->mTaskObserver.OnTaskAppControl(appControl);
+
+ app_control_destroy(appControl);
+ return 0;
+ }
+
+ void OnUiEvent(AppCoreTaskBase::UiState state) override
+ {
+ // This event is emitted when the UI thread is paused or resumed.
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnUiEvent() emitted", __MODULE__, __func__, __LINE__);
+
+ // Note: This isn't implemented.
+ AppCoreTaskBase::OnUiEvent(state);
+ }
+
+ void OnLowMemory(AppCoreTaskBase::LowMemoryState state) override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLowMemory() emitted", __MODULE__, __func__, __LINE__);
+
+ mNewMemoryStatus = AppCore::GetMemoryStatus(static_cast<app_event_low_memory_status_e>(state));
+
+ PostToUiThread(
+ [](gpointer userData) -> gboolean
+ {
+ auto* task = static_cast<Task*>(userData);
+ auto* framework = static_cast<Framework*>(task->mFramework);
+ framework->mObserver.OnMemoryLow(task->mNewMemoryStatus);
+ return G_SOURCE_REMOVE;
+ });
+ mFramework->mTaskObserver.OnTaskMemoryLow(mNewMemoryStatus);
+ AppCoreTaskBase::OnLowMemory(state);
+ }
+
+ void OnLowBattery(AppCoreTaskBase::LowBatteryState state) override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLowBattery() emitted", __MODULE__, __func__, __LINE__);
+ mNewBatteryStatus = AppCore::GetBatteryStatus(static_cast<app_event_low_battery_status_e>(state));
+
+ PostToUiThread(
+ [](gpointer userData) -> gboolean
+ {
+ auto* task = static_cast<Task*>(userData);
+ auto* framework = static_cast<Framework*>(task->mFramework);
+ framework->mObserver.OnBatteryLow(task->mNewBatteryStatus);
+ return G_SOURCE_REMOVE;
+ });
+ mFramework->mTaskObserver.OnTaskBatteryLow(mNewBatteryStatus);
+ AppCoreTaskBase::OnLowBattery(state);
+ }
+
+ void OnLangChanged(const std::string& lang) override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLangChanged() emitted", __MODULE__, __func__, __LINE__);
+ mNewLanguage = lang;
+ mFramework->SetLanguage(mNewLanguage);
+
+ PostToUiThread(
+ [](gpointer userData) -> gboolean
+ {
+ auto* task = static_cast<Task*>(userData);
+ auto* framework = static_cast<Framework*>(task->mFramework);
+ framework->mObserver.OnLanguageChanged();
+ return G_SOURCE_REMOVE;
+ });
+
+ mFramework->mTaskObserver.OnTaskLanguageChanged();
+ AppCoreTaskBase::OnLangChanged(lang);
+ }
+
+ void OnRegionChanged(const std::string& region) override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > nRegionChanged() emitted", __MODULE__, __func__, __LINE__);
+ mNewRegion = region;
+ mFramework->SetRegion(mNewRegion);
+
+ PostToUiThread(
+ [](gpointer userData) -> gboolean
+ {
+ auto* task = static_cast<Task*>(userData);
+ auto* framework = static_cast<Framework*>(task->mFramework);
+ framework->mObserver.OnRegionChanged();
+ return G_SOURCE_REMOVE;
+ });
+
+ mFramework->mTaskObserver.OnTaskRegionChanged();
+ AppCoreTaskBase::OnRegionChanged(mNewRegion);
+ }
+
+ void OnDeviceOrientationChanged(AppCoreTaskBase::DeviceOrientationState state) override
+ {
+ print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnDeviceOrientationChanged() emitted", __MODULE__, __func__, __LINE__);
+ // Note: This isn't emitted to the App.
+ AppCoreTaskBase::OnDeviceOrientationChanged(state);
+ }
+
+ private:
+ GMainContext* GetTizenGlibContext()
+ {
+ GMainContext* context;
+ const char* env = getenv("TIZEN_GLIB_CONTEXT");
+ if(env)
+ {
+ context = (GMainContext*)strtoul(env, nullptr, 10);
+ }
+ else
+ {
+ context = nullptr;
+ }
+
+ return context;
+ }
+
+ void PostToUiThread(GSourceFunc func)
+ {
+ GSource* source = g_idle_source_new();
+ g_source_set_callback(source, func, this, nullptr);
+ g_source_attach(source, GetTizenGlibContext());
+ g_source_unref(source);
+ }
+
+ private:
+ Framework* mFramework;
+ std::string mNewLanguage;
+ std::string mNewRegion;
+ Dali::DeviceStatus::Battery::Status mNewBatteryStatus;
+ Dali::DeviceStatus::Memory::Status mNewMemoryStatus;
+ };
+
explicit UiAppContext(unsigned int hint, Framework* framework)
: AppCoreUiBase(hint),
- mFramework(framework)
+ mFramework(framework),
+ mUseUiThread(false)
{
- mLanguageChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LANG_CHANGE, OnLanguageChanged, this);
- AddEvent(mLanguageChanged);
+ if(hint & AppCoreUiBase::HINT_DUAL_THREAD)
+ {
+ mUseUiThread = true;
+ }
+
+ if(!mUseUiThread)
+ {
+ mLanguageChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LANG_CHANGE, OnLanguageChanged, this);
+ AddEvent(mLanguageChanged);
- mDeviceOrientationChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, OnDeviceOrientationChanged, this);
- AddEvent(mDeviceOrientationChanged);
+ mDeviceOrientationChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, OnDeviceOrientationChanged, this);
+ AddEvent(mDeviceOrientationChanged);
- mRegionFormatChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::REGION_CHANGE, OnRegionFormatChanged, this);
- AddEvent(mRegionFormatChanged);
+ mRegionFormatChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::REGION_CHANGE, OnRegionFormatChanged, this);
+ AddEvent(mRegionFormatChanged);
- mLowMemory = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_MEMORY, OnLowMemory, this);
- AddEvent(mLowMemory);
+ mLowMemory = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_MEMORY, OnLowMemory, this);
+ AddEvent(mLowMemory);
- mLowBattery = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_BATTERY, OnLowBattery, this);
- AddEvent(mLowBattery);
+ mLowBattery = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_BATTERY, OnLowBattery, this);
+ AddEvent(mLowBattery);
+ }
}
virtual ~UiAppContext()
{
- RemoveEvent(mLowBattery);
- RemoveEvent(mLowMemory);
- RemoveEvent(mRegionFormatChanged);
- RemoveEvent(mDeviceOrientationChanged);
- RemoveEvent(mLanguageChanged);
+ if(!mUseUiThread)
+ {
+ RemoveEvent(mLowBattery);
+ RemoveEvent(mLowMemory);
+ RemoveEvent(mRegionFormatChanged);
+ RemoveEvent(mDeviceOrientationChanged);
+ RemoveEvent(mLanguageChanged);
+ }
+ }
+
+ std::unique_ptr<AppCoreTaskBase> CreateTask() override
+ {
+ return std::unique_ptr<AppCoreTaskBase>(
+ new Task(mFramework));
}
int OnCreate() override
std::shared_ptr<AppEvent> mRegionFormatChanged;
std::shared_ptr<AppEvent> mLowBattery;
std::shared_ptr<AppEvent> mLowMemory;
+ bool mUseUiThread;
};
// Constructor
- Impl(void* data, Type type)
+ Impl(void* data, Type type, bool useUiThread)
: mAbortCallBack(NULL),
- mCallbackManager(NULL)
+ mCallbackManager(NULL),
+ mUseUiThread(useUiThread)
#ifdef APPCORE_WATCH_AVAILABLE
,
mWatchCallback()
Framework* mFramework;
AppCore::AppEventHandlerPtr handlers[5];
std::unique_ptr<UiAppContext> mUiAppContext;
+ bool mUseUiThread;
#ifdef APPCORE_WATCH_AVAILABLE
watch_app_lifecycle_callback_s mWatchCallback;
app_event_handler_h watchHandlers[5];
AppCoreUiBase::HINT_HW_ACC_CONTROL |
AppCoreUiBase::HINT_WINDOW_AUTO_CONTROL;
+ // For testing UIThread model, This code turns on the UI Thread feature forcibly.
+ // ex) app_launcher -e [APPID] __K_UI_THREAD enable
+ // This code doesn't change mUseUiThread in Internal::Application
+ bundle* b = bundle_import_from_argv(*mFramework->mArgc, *mFramework->mArgv);
+ if(b != nullptr)
+ {
+ const char* val = bundle_get_val(b, "__K_UI_THREAD");
+ if(val != nullptr && strcmp(val, "enable") == 0)
+ {
+ mUseUiThread = true;
+ }
+
+ bundle_free(b);
+ }
+
+ if(mUseUiThread)
+ {
+ hint |= AppCoreUiBase::HINT_DUAL_THREAD;
+ }
+
mUiAppContext = std::make_unique<UiAppContext>(hint, mFramework);
}
Impl& operator=(const Impl& impl);
};
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
: mObserver(observer),
+ mTaskObserver(taskObserver),
mInitialised(false),
mPaused(false),
mRunning(false),
InitThreads();
- mImpl = new Impl(this, type);
+ mImpl = new Impl(this, type, useUiThread);
}
Framework::~Framework()
}
WatchApplication::WatchApplication(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode)
-: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::WATCH, WindowType::NORMAL),
+: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::WATCH, WindowType::NORMAL, false),
mState(UNINITIALIZED)
{
}
}
};
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
: mObserver(observer),
+ mTaskObserver(taskObserver),
mInitialised(false),
mPaused(false),
mRunning(false),
std::string mRegion;\r
};\r
\r
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)\r
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)\r
: mObserver(observer),\r
+ mTaskObserver(taskObserver),\r
mInitialised(false),\r
mPaused(false),\r
mRunning(false),\r
#define DALI_ENV_SUPPRESS_SCREEN_READER "DALI_SUPPRESS_SCREEN_READER"
+#define DALI_ENV_ENABLE_UI_THREAD "DALI_ENABLE_UI_THREAD"
+
} // namespace Adaptor
} // namespace Internal
}
WidgetApplication::WidgetApplication(int* argc, char** argv[], const std::string& stylesheet)
-: Application(argc, argv, stylesheet, Dali::WidgetApplication::OPAQUE, PositionSize(), Framework::WIDGET, WindowType::NORMAL)
+: Application(argc, argv, stylesheet, Dali::WidgetApplication::OPAQUE, PositionSize(), Framework::WIDGET, WindowType::NORMAL, false)
{
DALI_LOG_ERROR("WidgetApplication is not implemented in UBUNTU profile.\n");
}
mEcoreEventHandler.PushBack(ecore_event_handler_add(ECORE_WL_EVENT_SELECTION_DATA_READY, EcoreEventDataReceive, this));
// Register Vconf notify - font name and size
- vconf_notify_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
- vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
+ vconf_notify_key_changed_for_ui_thread(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
+ vconf_notify_key_changed_for_ui_thread(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
mDisplay = ecore_wl_display_get();
mEcoreEventHandler.PushBack(ecore_event_handler_add(ECORE_WL2_EVENT_AUX_MESSAGE, EcoreEventWindowAuxiliaryMessage, this));
// Register Vconf notify - font name and size
- vconf_notify_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
- vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
+ vconf_notify_key_changed_for_ui_thread(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
+ vconf_notify_key_changed_for_ui_thread(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
mDisplay = ecore_wl2_display_get(display);
}
else
{
- internal = Internal::Adaptor::Application::New(argc, argv, "", OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+ internal = Internal::Adaptor::Application::New(argc, argv, "", OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
}
return Application(internal.Get());
}
}
else
{
- internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+ internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
}
return Application(internal.Get());
}
}
else
{
- internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+ internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
}
return Application(internal.Get());
}
}
else
{
- internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+ internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
+ }
+ return Application(internal.Get());
+}
+
+Application Application::New(int* argc, char** argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize, bool useUiThread)
+{
+ Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+ if(internal)
+ {
+ // pre-initialized application
+ internal->SetCommandLineOptions(argc, argv);
+ if(argc && (*argc > 0))
+ {
+ internal->GetWindow().SetClass((*argv)[0], "");
+ }
+ internal->SetStyleSheet(stylesheet);
+
+ internal->GetWindow().SetTransparency((windowMode == Application::OPAQUE ? false : true));
+
+ //Store only the value before adaptor is created
+ internal->StoreWindowPositionSize(positionSize);
+ }
+ else
+ {
+ internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, useUiThread);
}
return Application(internal.Get());
}
return Internal::Adaptor::GetImplementation(*this).LowMemorySignal();
}
+Application::AppSignalType& Application::TaskInitSignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskInitSignal();
+}
+
+Application::AppSignalType& Application::TaskTerminateSignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskTerminateSignal();
+}
+
+Application::AppControlSignalType& Application::TaskAppControlSignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskAppControlSignal();
+}
+
+Application::AppSignalType& Application::TaskLanguageChangedSignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskLanguageChangedSignal();
+}
+
+Application::AppSignalType& Application::TaskRegionChangedSignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskRegionChangedSignal();
+}
+
+Application::LowBatterySignalType& Application::TaskLowBatterySignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskLowBatterySignal();
+}
+
+Application::LowMemorySignalType& Application::TaskLowMemorySignal()
+{
+ return Internal::Adaptor::GetImplementation(*this).TaskLowMemorySignal();
+}
+
Application::Application(Internal::Adaptor::Application* application)
: BaseHandle(application)
{
* app.ResumeSignal().Connect(&app, &MyApplication::Resume);
* @endcode
*
+ *
+ * #### UI thread
+ * There is the UI thread feature.
+ * UI thread is an additional thread that an Application object creates. The thread is for UI events.
+ *
+ * When the UI thread feature is enabled, you can use the task signals(TaskInit, TaskTerminate, TaskAppControl, TaskLanguageChanged, TaskLowBattery, and TaskLowMemory).
+ * The task signals are emitted on the main thread,
+ * and the normal signals(Init, Terminate, Pause, Resume, Reset, AppControl, LanguageChanged, Region, LowBattery, and LowMemory) are emitted on the UI thread.
+ *
+ * If you want to handle windows or actors in cases like when the memory level of the device is low, you have to use the normal signals, not the task signals.
+ * Callbacks of all signals in DALi except the task signals are emitted on the UI thread. (e.g., Timer callbacks are emitted on the UI thread.)
+ *
+ * To enable the UI Thread, you can use this method. you have to set True to the useUiThread.
+ * Dali::Application::New(int *argc, char **argv[], const std::string &stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize, bool useUiThread)
+ *
+ *
* This class accepts command line arguments as well. The following options are supported:
*
* @code
static Application New(int* argc, char** argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize);
/**
+ * @brief This is the constructor for applications.
+ *
+ * @SINCE_2_1.20
+ * @PRIVLEVEL_PUBLIC
+ * @PRIVILEGE_DISPLAY
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer to the argument list
+ * @param[in] stylesheet The path to user defined theme file
+ * @param[in] windowMode A member of WINDOW_MODE
+ * @param[in] positionSize A position and a size of the window
+ * @param[in] useUiThread True if the application would create a UI thread
+ * @return A handle to the Application
+ * @note If the stylesheet is not specified, then the library's default stylesheet will not be overridden.<BR>
+ * UI thread is an additional thread that DALi creates for UI events.
+ * The UI thread isn't blocked from the system events(AppControl, LanguageChanged, RegionChanged, LowMemory, LowBattery task signals).
+ */
+ static Application New(int* argc, char** argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize, bool useUiThread);
+
+ /**
* @brief Constructs an empty handle.
* @SINCE_1_0.0
*/
/**
* @brief The user should connect to this signal to determine when they should initialize
* their application.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_0.0
* @return The signal to connect to
*/
/**
* @brief The user should connect to this signal to determine when they should terminate
* their application.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_0.0
* @return The signal to connect to
*/
/**
* @brief The user should connect to this signal if they need to perform any special
* activities when the application is about to be paused.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_0.0
* @return The signal to connect to
*/
/**
* @brief The user should connect to this signal if they need to perform any special
* activities when the application has resumed.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_0.0
* @return The signal to connect to
*/
/**
* @brief This signal is sent when the system requires the user to reinitialize itself.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_0.0
* @return The signal to connect to
*/
AppSignalType& ResetSignal();
/**
- * @brief This signal is emitted when another application sends a launch request to the application.
- *
- * When the application is launched, this signal is emitted after the main loop of the application starts up.
- * The passed parameter describes the launch request and contains the information about why the application is launched.
- * @SINCE_1_0.0
- * @return The signal to connect to
- */
+ * @brief This signal is emitted when another application sends a launch request to the application.
+ *
+ * When the application is launched, this signal is emitted after the main loop of the application starts up.
+ * The passed parameter describes the launch request and contains the information about why the application is launched.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
+ * @SINCE_1_0.0
+ * @return The signal to connect to
+ */
AppControlSignalType& AppControlSignal();
/**
* @brief This signal is emitted when the language is changed on the device.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_0.0
* @return The signal to connect to
*/
AppSignalType& LanguageChangedSignal();
/**
- * @brief This signal is emitted when the region of the device is changed.
- * @SINCE_1_0.0
- * @return The signal to connect to
- */
+ * @brief This signal is emitted when the region of the device is changed.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
+ * @SINCE_1_0.0
+ * @return The signal to connect to
+ */
AppSignalType& RegionChangedSignal();
/**
* @brief This signal is emitted when the battery level of the device is low.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_2.62
* @return The signal to connect to
*/
/**
* @brief This signal is emitted when the memory level of the device is low.
+ * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+ * Otherwise, it is emitted on the main thread.
* @SINCE_1_2.62
* @return The signal to connect to
*/
LowMemorySignalType& LowMemorySignal();
+ // TaskSignal
+ /**
+ * @brief The user should connect to this signal to determine when they should initialize
+ * their application.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ AppSignalType& TaskInitSignal();
+
+ /**
+ * @brief The user should connect to this signal to determine when they should terminate
+ * their application.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ AppSignalType& TaskTerminateSignal();
+
+ /**
+ * @brief This signal is emitted when another application sends a launch request to the application.
+ *
+ * When the application is launched, this signal is emitted after the main loop of the application starts up.
+ * The passed parameter describes the launch request and contains the information about why the application is launched.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ AppControlSignalType& TaskAppControlSignal();
+
+ /**
+ * @brief This signal is emitted when the language is changed on the device.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ AppSignalType& TaskLanguageChangedSignal();
+
+ /**
+ * @brief This signal is emitted when the region of the device is changed.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ AppSignalType& TaskRegionChangedSignal();
+
+ /**
+ * @brief This signal is emitted when the battery level of the device is low.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ LowBatterySignalType& TaskLowBatterySignal();
+
+ /**
+ * @brief This signal is emitted when the memory level of the device is low.
+ * Only when the user uses the UiThread, this signal is emitted on the main thread.
+ * Otherwise, it is not emitted at all.
+ * @return The signal to connect to
+ */
+ LowMemorySignalType& TaskLowMemorySignal();
+
public: // Not intended for application developers
/// @cond internal
/**