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());
}
*/
enum class ColorFormat
{
- RGB888, /// 8 red bits, 8 green bits, 8 blue bits
- RGBA8888, /// 8 red bits, 8 green bits, 8 blue bits, alpha 8 bits
- RGBX8888, /// 8 red bits, 8 green bits, 8 blue bits, and 8 ignored bits
- BGR888, /// 8 blue bits, 8 green bits, 8 red bits
- BGRA8888, /// 8 blue bits, 8 green bits, 8 red bits, alpha 8 bits
- BGRX8888, /// 8 blue bits, 8 green bits, 8 red bits, and 8 ignored bits
+ BGR888 = 0, /// 8 blue bits, 8 green bits, 8 red bits
+ BGRA8888 = 1, /// 8 blue bits, 8 green bits, 8 red bits, alpha 8 bits
+ BGRX8888 = 2, /// 8 blue bits, 8 green bits, 8 red bits, and 8 ignored bits
+ RGB888 = 3, /// 8 red bits, 8 green bits, 8 blue bits
+ RGBA8888 = 4, /// 8 red bits, 8 green bits, 8 blue bits, alpha 8 bits
+ RGBX8888 = 5, /// 8 red bits, 8 green bits, 8 blue bits, and 8 ignored bits
};
/**
}
};
-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
/**