GLIB implementation 37/280037/3
authorDavid Steele <david.steele@samsung.com>
Mon, 22 Aug 2022 17:39:03 +0000 (18:39 +0100)
committerDavid Steele <david.steele@samsung.com>
Thu, 25 Aug 2022 14:27:54 +0000 (15:27 +0100)
Got timers working
FD polling works (and doesn't need X11 to use POLLOUT)
Idle functions working

Change-Id: I8cfa5302eb6e3fa4a8818a4fa645a9d2d6daf4a1
Signed-off-by: David Steele <david.steele@samsung.com>
15 files changed:
build/tizen/CMakeLists.txt
build/tizen/deps-check.cmake
build/tizen/profiles/glib-x11-profile.cmake [new file with mode: 0644]
dali/internal/accessibility/file.list
dali/internal/adaptor/common/adaptor-impl.cpp
dali/internal/adaptor/file.list
dali/internal/adaptor/glib/framework-glib.cpp [new file with mode: 0644]
dali/internal/clipboard/file.list
dali/internal/system/file.list
dali/internal/system/glib/callback-manager-glib.cpp [new file with mode: 0644]
dali/internal/system/glib/callback-manager-glib.h [new file with mode: 0644]
dali/internal/system/glib/file-descriptor-monitor-glib.cpp [new file with mode: 0644]
dali/internal/system/glib/timer-impl-glib.cpp [new file with mode: 0644]
dali/internal/system/ubuntu-x11/logging-x.cpp
dali/internal/window-system/x11/window-system-x.cpp

index 5ade4b7..75d2f6c 100644 (file)
@@ -106,13 +106,13 @@ IF( UNIX )
   INCLUDE( deps-check.cmake )
 ENDIF()
 
-IF( UBUNTU_PROFILE OR ANDROID_PROFILE OR WIN32 OR APPLE OR LIBUV_X11_PROFILE )
+IF( UBUNTU_PROFILE OR ANDROID_PROFILE OR WIN32 OR APPLE OR LIBUV_X11_PROFILE OR GLIB_X11_PROFILE)
   SET( ENABLE_VCONF OFF )
 ELSE()
   SET( ENABLE_VCONF ON )
 ENDIF()
 
-IF( NOT DALI_ELDBUS_AVAILABLE OR LIBUV_X11_PROFILE )
+IF( NOT DALI_ELDBUS_AVAILABLE OR LIBUV_X11_PROFILE OR GLIB_X11_PROFILE)
   SET( ENABLE_ATSPI OFF )
 ENDIF()
 
index 968b083..66028c0 100755 (executable)
@@ -42,7 +42,7 @@ IF( NOT enable_profile )
 ENDIF()
 
 # Test for profile and exit if something wrong
-SET( VALID_PROFILES COMMON MOBILE WEARABLE TV IVI UBUNTU ANDROID WINDOWS MACOS LIBUV_X11)
+SET( VALID_PROFILES COMMON MOBILE WEARABLE TV IVI UBUNTU ANDROID WINDOWS MACOS LIBUV_X11 GLIB_X11)
 LIST( FIND VALID_PROFILES ${enable_profile} RESULT )
 IF( RESULT EQUAL -1 )
   MESSAGE( FATAL_ERROR "Invalid profile!" )
@@ -51,7 +51,7 @@ ENDIF()
 # Defines profile specific variable
 SET( ${enable_profile}_PROFILE 1 )
 
-IF( LIBUV_X11_PROFILE )
+IF( LIBUV_X11_PROFILE OR GLIB_X11_PROFILE )
   SET( X11_REQUIRED 1 )
 ENDIF()
 
@@ -102,6 +102,7 @@ CHECK_MODULE_AND_SET( DLOG dlog [] )
 CHECK_MODULE_AND_SET( TTS tts [] )
 CHECK_MODULE_AND_SET( VCONF vconf [] )
 CHECK_MODULE_AND_SET( LIBUV libuv [] )
+CHECK_MODULE_AND_SET( GLIB glib-2.0 [] )
 CHECK_MODULE_AND_SET( X11 x11 [] )
 CHECK_MODULE_AND_SET( XDAMAGE xdamage [] )
 CHECK_MODULE_AND_SET( XFIXES xfixes [] )
@@ -333,7 +334,7 @@ ENDIF()
 ENDIF()
 
 # Android includes pthread with android lib
-if( NOT ANDROID_PROFILE )
+IF( NOT ANDROID_PROFILE )
   SET( DALI_LDFLAGS ${DALI_LDFLAGS}
     -lpthread
   )
@@ -364,10 +365,10 @@ IF( ANDROID_PROFILE )
   )
 ENDIF()
 
+
 IF(X11_REQUIRED)
 
   SET( DALI_CFLAGS ${DALI_CFLAGS}
-    ${LIBUV_CFLAGS}
     ${X11_CFLAGS}
     ${XDAMAGE_CFLAGS}
     ${XFIXES_CFLAGS}
@@ -375,7 +376,6 @@ IF(X11_REQUIRED)
     )
 
   SET( DALI_LDFLAGS ${DALI_LDFLAGS}
-    ${LIBUV_LDFLAGS}
     ${X11_LDFLAGS}
     ${XDAMAGE_LDFLAGS}
     ${XFIXES_LDFLAGS}
@@ -453,6 +453,15 @@ IF( WAYLAND )
   )
 ENDIF()
 
+IF(LIBUV_X11_PROFILE)
+  SET(DALI_CFLAGS ${DALI_CFLAGS} ${LIBUV_CFLAGS})
+  SET(DALI_LDFLAGS ${DALI_LDFLAGS} ${LIBUV_LDFLAGS})
+ELSEIF(GLIB_X11_PROFILE)
+  SET(DALI_CFLAGS ${DALI_CFLAGS} ${GLIB_CFLAGS})
+  SET(DALI_LDFLAGS ${DALI_LDFLAGS} ${GLIB_LDFLAGS})
+ENDIF()
+
+
 # COMMON PROFILE
 IF( COMMON_PROFILE )
   SET( DALI_CFLAGS ${DALI_CFLAGS} ${HAPTIC_CFLAGS} )
@@ -509,10 +518,15 @@ ENDIF()
 # UBUNTU PROFILE
 IF( UBUNTU_PROFILE )
   SET( DALI_CFLAGS ${DALI_CFLAGS} -fPIC )
-  SET( DALI_LDFLAGS ${DALI_LDFLAGS} -ljpeg )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS} -ljpeg)
+ENDIF()
+
+# Dali depends on shm_open, but librt is usually included from framework (ecore, libuv etc)
+IF( GLIB_X11_PROFILE)
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS} -lrt)
 ENDIF()
 
-IF( NOT COMMON_PROFILE )
+IF( NOT COMMON_PROFILE AND NOT X11_REQUIRED)
   ADD_DEFINITIONS( -DWAYLAND_EXTENSIONS_SUPPORTED )
 ENDIF()
 
diff --git a/build/tizen/profiles/glib-x11-profile.cmake b/build/tizen/profiles/glib-x11-profile.cmake
new file mode 100644 (file)
index 0000000..7914fb0
--- /dev/null
@@ -0,0 +1,158 @@
+# PROFILE: GLIB_X11
+
+# Set the sources
+SET( SOURCES
+        ${adaptor_accessibility_common_src_files}
+        ${adaptor_accessibility_glib_x11_src_files}
+        ${adaptor_adaptor_common_src_files}
+        ${adaptor_adaptor_glib_src_files}
+        ${adaptor_addons_common_src_files}
+        ${adaptor_addons_ubuntu_src_files}
+        ${adaptor_camera_common_src_files}
+        ${adaptor_canvas_renderer_generic_src_files}
+        ${adaptor_clipboard_common_src_files}
+        ${adaptor_clipboard_glib_x11_src_files}
+        ${adaptor_drag_and_drop_generic_src_files}
+        ${adaptor_framework_generic_src_files}
+        ${devel_api_src_files}
+        ${adaptor_devel_api_text_abstraction_src_files}
+        ${adaptor_graphics_common_src_files}
+        ${adaptor_graphics_gles_src_files}
+        ${adaptor_graphics_x11_src_files}
+        ${adaptor_haptics_common_src_files}
+        ${adaptor_imaging_common_src_files}
+        ${adaptor_imaging_x11_src_files}
+        ${adaptor_input_common_src_files}
+        ${adaptor_input_generic_src_files}
+        ${adaptor_integration_api_src_files}
+        ${adaptor_legacy_common_src_files}
+        ${adaptor_network_common_src_files}
+        ${adaptor_offscreen_common_src_files}
+        ${adaptor_public_api_src_files}
+        ${adaptor_sensor_common_src_files}
+        ${adaptor_styling_common_src_files}
+        ${adaptor_system_common_src_files}
+        ${adaptor_system_glib_src_files}
+        ${adaptor_resampler_src_files}
+        ${adaptor_text_common_src_files}
+        ${adaptor_thread_common_src_files}
+        ${adaptor_trace_common_src_files}
+        ${adaptor_vector_animation_common_src_files}
+        ${adaptor_vector_image_common_src_files}
+        ${adaptor_video_common_src_files}
+        ${adaptor_web_engine_common_src_files}
+        ${adaptor_window_system_common_src_files}
+        ${adaptor_window_system_x11_src_files}
+        ${devel_api_text_abstraction_src_files}
+        ${static_libraries_libunibreak_src_files}
+)
+
+IF( ENABLE_VECTOR_BASED_TEXT_RENDERING )
+    SET( SOURCES ${SOURCES}
+         ${static_libraries_glyphy_src_files}
+    )
+ENDIF()
+
+IF( NOT thorvg_support)
+    SET( SOURCES ${SOURCES}
+         ${static_libraries_nanosvg_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+          ${adaptor_performance_logging_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+        ${adaptor_trace_generic_src_files}
+      )
+ENDIF()
+
+# Set the header directories
+SET( PROFILE_INCLUDE_DIRECTORIES
+        ${EXIF_INCLUDE_DIRS}
+        ${FREETYPE_INCLUDE_DIRS}
+        ${FREETYPE_BITMAP_SUPPORT}
+        ${FONTCONFIG_INCLUDE_DIRS}
+        ${PNG_INCLUDE_DIRS}
+        ${LIBEXIF_INCLUDE_DIRS}
+        ${LIBDRM_INCLUDE_DIRS}
+        ${LIBCURL_INCLUDE_DIRS}
+        ${LIBCRYPTO_INCLUDE_DIRS}
+        ${HARFBUZZ_INCLUDE_DIRS}
+        ${FRIBIDI_INCLUDE_DIRS}
+        ${CAIRO_INCLUDE_DIRS}
+        ${CAPI_APPFW_APPLICATION_INCLUDE_DIRS}
+        ${X11_INCLUDE_DIRS}
+        ${DALICORE_INCLUDE_DIRS}
+        )
+
+# Set compile options
+ADD_COMPILE_OPTIONS(
+  ${DALI_ADAPTOR_CFLAGS}
+  ${DALICORE_CFLAGS}
+  ${OPENGLES20_CFLAGS}
+  ${FREETYPE_CFLAGS}
+  ${FONTCONFIG_CFLAGS}
+  ${CAIRO_CFLAGS}
+  ${PNG_CFLAGS}
+  ${DLOG_CFLAGS}
+  ${VCONF_CFLAGS}
+  ${EXIF_CFLAGS}
+  ${MMFSOUND_CFLAGS}
+  ${TTS_CFLAGS}
+  ${CAPI_SYSTEM_SENSOR_CFLAGS}
+  ${LIBDRM_CFLAGS}
+  ${LIBEXIF_CFLAGS}
+  ${LIBCURL_CFLAGS}
+  ${LIBCRYPTO_CFLAGS}
+  ${UTILX_CFLAGS}
+)
+
+# Set the linker flags
+SET(REQUIRED_LIBS
+  ${EXIF_LDFLAGS}
+  ${FREETYPE_LDFLAGS}
+  ${FREETYPE_BITMAP_SUPPORT}
+  ${FONTCONFIG_LDFLAGS}
+  ${PNG_LDFLAGS}
+  ${LIBEXIF_LDFLAGS}
+  ${LIBDRM_LDFLAGS}
+  ${LIBCURL_LDFLAGS}
+  ${LIBCRYPTO_LDFLAGS}
+  ${HARFBUZZ_LDFLAGS}
+  ${FRIBIDI_LDFLAGS}
+  ${CAIRO_LDFLAGS}
+  ${CAPI_APPFW_APPLICATION_LDFLAGS}
+  ${X11_LDFLAGS}
+  ${DALICORE_LDFLAGS}
+  ${OPENGLES20_LDFLAGS}
+  ${EGL_LDFLAGS}
+  -lgif
+  -lpthread
+  -lturbojpeg
+  -ljpeg
+  -lhyphen
+)
+
+
+FIND_LIBRARY( HYPHEN_LIBRARY NAMES hyphen )
+IF (${HYPHEN_LIBRARY} MATCHES "HYPHEN_LIBRARY-NOTFOUND")
+  UNSET (HYPHEN_LIBRARY_AVAILABLE)
+ELSE()
+  SET (HYPHEN_LIBRARY_AVAILABLE "HYPHEN_LIBRARY_AVAILABLE")
+  ADD_DEFINITIONS(-DHYPHEN_LIBRARY_AVAILABLE="${HYPHEN_LIBRARY_AVAILABLE}")
+
+  #The path of hyphen library dictionary
+  IF (NOT "${HYPHEN_DIC}")
+  FIND_PATH(HYPHEN_DIC hyph_en_US.dic HINTS "/usr/local/share/hyphen" "/usr/share/hyphen" )
+  IF ( NOT HYPHEN_DIC MATCHES  "HYPHEN_DIC-NOTFOUND")
+    ADD_DEFINITIONS(-DHYPHEN_DIC="${HYPHEN_DIC}")
+  ENDIF()
+  ENDIF()
+  MESSAGE (HYPHEN_DIC: "${HYPHEN_DIC}")
+
+ENDIF()
index ebfcb6f..3f3e35c 100644 (file)
@@ -49,6 +49,12 @@ SET( adaptor_accessibility_libuv_x11_src_files
     ${adaptor_accessibility_dir}/generic/tts-player-impl-generic.cpp
 )
 
+# module: accessibility, backend: glib_x11 profile
+SET( adaptor_accessibility_glib_x11_src_files
+    ${adaptor_accessibility_dir}/generic/tts-player-factory-generic.cpp
+    ${adaptor_accessibility_dir}/generic/tts-player-impl-generic.cpp
+)
+
 # module: accessibility, backend: windows
 SET( adaptor_accessibility_windows_src_files
 )
index 5084234..d884b92 100644 (file)
@@ -913,13 +913,13 @@ void Adaptor::ProcessCoreEvents()
       mPerformanceInterface->AddMarker(PerformanceInterface::PROCESS_EVENTS_START);
     }
 
-#if !defined(DALI_PROFILE_UBUNTU) && !defined(DALI_PROFILE_LIBUV_X11)
+#if !defined(DALI_PROFILE_UBUNTU) && !defined(DALI_PROFILE_LIBUV_X11) && !defined(DALI_PROFILE_GLIB_X11)
     DALI_LOG_RELEASE_INFO("Start ProcessEvents\n");
 #endif
 
     mCore->ProcessEvents();
 
-#if !defined(DALI_PROFILE_UBUNTU) && !defined(DALI_PROFILE_LIBUV_X11)
+#if !defined(DALI_PROFILE_UBUNTU) && !defined(DALI_PROFILE_LIBUV_X11) && !defined(DALI_PROFILE_GLIB_X11)
     DALI_LOG_RELEASE_INFO("End ProcessEvents\n");
 #endif
 
index 93cd8a7..3dae4b5 100644 (file)
@@ -22,6 +22,12 @@ SET( adaptor_adaptor_libuv_src_files
     ${adaptor_adaptor_dir}/libuv/framework-libuv.cpp
 )
 
+# module: adaptor, backend: glib-x11
+SET( adaptor_adaptor_glib_src_files
+    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp
+    ${adaptor_adaptor_dir}/glib/framework-glib.cpp
+)
+
 # module: adaptor, backend: tizen-wearable
 SET( adaptor_adaptor_tizen_wearable_src_files
     ${adaptor_adaptor_dir}/tizen-wayland/tizen-wearable/watch-application.cpp
diff --git a/dali/internal/adaptor/glib/framework-glib.cpp b/dali/internal/adaptor/glib/framework-glib.cpp
new file mode 100644 (file)
index 0000000..9b2842f
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/framework.h>
+
+// EXTERNAL INCLUDES
+#include <glib.h>
+#include <cstdio>
+#include <cstring>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+thread_local GMainLoop* gMainLoop{nullptr};
+
+GMainContext* GetMainLoopContext()
+{
+  if(gMainLoop != nullptr)
+  {
+    return g_main_loop_get_context(gMainLoop);
+  }
+  return nullptr;
+}
+
+/**
+ * Impl to hide GLib data members
+ */
+struct Framework::Impl
+{
+  // Constructor
+  Impl(void* data)
+  : mAbortCallBack(nullptr),
+    mCallbackManager(nullptr),
+    mLanguage("NOT_SUPPORTED"),
+    mRegion("NOT_SUPPORTED")
+  {
+    mCallbackManager = CallbackManager::New();
+
+    // In future, may need to change this to have own context or use Tizen context
+    gMainLoop = mMainLoop = g_main_loop_new(nullptr, false);
+  }
+
+  ~Impl()
+  {
+    delete mAbortCallBack;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+
+    g_main_loop_unref(mMainLoop);
+    gMainLoop = nullptr;
+  }
+
+  void Run()
+  {
+    g_main_loop_run(mMainLoop);
+  }
+
+  void Quit()
+  {
+    g_main_loop_quit(mMainLoop);
+  }
+
+  // Data
+  CallbackBase*    mAbortCallBack;
+  CallbackManager* mCallbackManager;
+  GMainLoop*       mMainLoop{nullptr};
+  GMainContext*    mContext{nullptr};
+
+  std::string mLanguage;
+  std::string mRegion;
+
+private:
+  Impl(const Impl& impl) = delete;
+  Impl& operator=(const Impl& impl) = delete;
+};
+
+Framework::Framework(Framework::Observer& observer, TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
+: mObserver(observer),
+  mTaskObserver(taskObserver),
+  mInitialised(false),
+  mRunning(false),
+  mArgc(argc),
+  mArgv(argv),
+  mBundleName(""),
+  mBundleId(""),
+  mAbortHandler(MakeCallback(this, &Framework::AbortCallback)),
+  mImpl(NULL)
+{
+  mImpl = new Impl(this);
+}
+
+Framework::~Framework()
+{
+  if(mRunning)
+  {
+    Quit();
+  }
+
+  delete mImpl;
+}
+
+void Framework::Run()
+{
+  mRunning = true;
+  mObserver.OnInit();
+  mImpl->Run();
+
+  mRunning = false;
+}
+
+void Framework::Quit()
+{
+  mObserver.OnTerminate();
+  mImpl->Quit();
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback(CallbackBase* callback)
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+}
+
+std::string Framework::GetBundleId() const
+{
+  return "";
+}
+
+std::string Framework::GetResourcePath()
+{
+  // "DALI_APPLICATION_PACKAGE" is used by Ubuntu specifically to get the already configured Application package path.
+  const char* ubuntuEnvironmentVariable = "DALI_APPLICATION_PACKAGE";
+  char*       value                     = getenv(ubuntuEnvironmentVariable);
+  std::string resourcePath;
+  if(value != NULL)
+  {
+    resourcePath = value;
+  }
+
+  if(resourcePath.back() != '/')
+  {
+    resourcePath += "/";
+  }
+
+  return resourcePath;
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+}
+
+void Framework::AbortCallback()
+{
+  // if an abort call back has been installed run it.
+  if(mImpl->mAbortCallBack)
+  {
+    CallbackBase::Execute(*mImpl->mAbortCallBack);
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+bool Framework::AppStatusHandler(int type, void* bundleData)
+{
+  return true;
+}
+
+std::string Framework::GetLanguage() const
+{
+  return mImpl->mLanguage;
+}
+
+std::string Framework::GetRegion() const
+{
+  return mImpl->mRegion;
+}
+
+std::string Framework::GetDataPath()
+{
+  const char* ubuntuEnvironmentVariable = "DALI_APPLICATION_DATA_DIR";
+  char*       value                     = getenv(ubuntuEnvironmentVariable);
+  std::string dataPath;
+  if(value != NULL)
+  {
+    dataPath = value;
+  }
+
+  return dataPath;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
index f2fe20c..25aa317 100644 (file)
@@ -33,3 +33,8 @@ SET( adaptor_clipboard_macos_src_files
 SET( adaptor_clipboard_libuv_x11_src_files
     ${adaptor_clipboard_dir}/generic/clipboard-impl-generic.cpp
 )
+
+# module: clipboard, backend: glib-x11
+SET( adaptor_clipboard_glib_x11_src_files
+    ${adaptor_clipboard_dir}/generic/clipboard-impl-generic.cpp
+)
index b9b92a9..07ca29c 100644 (file)
@@ -83,6 +83,21 @@ SET( adaptor_system_libuv_src_files
     ${adaptor_system_dir}/ubuntu-x11/widget-controller-x.cpp
 )
 
+# module: system, backend: glib-x11
+SET( adaptor_system_glib_src_files
+    ${adaptor_system_dir}/common/shared-file.cpp
+    ${adaptor_system_dir}/common/time-service.cpp
+    ${adaptor_system_dir}/common/trigger-event.cpp
+    ${adaptor_system_dir}/common/trigger-event-factory.cpp
+    ${adaptor_system_dir}/generic/shared-file-operations-generic.cpp
+    ${adaptor_system_dir}/glib/callback-manager-glib.cpp
+    ${adaptor_system_dir}/glib/file-descriptor-monitor-glib.cpp
+    ${adaptor_system_dir}/glib/timer-impl-glib.cpp
+    ${adaptor_system_dir}/ubuntu-x11/logging-x.cpp
+    ${adaptor_system_dir}/ubuntu-x11/system-settings-x.cpp
+    ${adaptor_system_dir}/ubuntu-x11/widget-application-impl-x.cpp
+    ${adaptor_system_dir}/ubuntu-x11/widget-controller-x.cpp
+)
 
 # module: system, backend: android
 SET( adaptor_system_android_src_files
diff --git a/dali/internal/system/glib/callback-manager-glib.cpp b/dali/internal/system/glib/callback-manager-glib.cpp
new file mode 100644 (file)
index 0000000..f6724da
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/glib/callback-manager-glib.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <glib.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+extern GMainContext* GetMainLoopContext();
+
+/**
+ * Structure contains the callback function and control options
+ */
+struct CallbackData
+{
+  typedef gboolean (*CallbackFunction)(gpointer userData);
+
+  /**
+   * Constructor
+   */
+  CallbackData(CallbackBase* callback, bool hasReturnValue)
+  : mCallback(callback),
+    mHasReturnValue(hasReturnValue)
+  {
+  }
+
+  /**
+   * Add the idle callback
+   */
+  void AddIdle()
+  {
+    GMainContext* context = GetMainLoopContext();
+    if(context != nullptr)
+    {
+      mSource = g_idle_source_new();
+      g_source_set_priority(mSource, G_PRIORITY_HIGH_IDLE);
+      g_source_set_callback(mSource, &CallbackData::IdleCallback, this, nullptr); // No destroyNotify
+      guint id = g_source_attach(mSource, context);
+    }
+  }
+
+  /**
+   * Destructor
+   */
+  ~CallbackData()
+  {
+    g_source_destroy(mSource);
+    g_source_unref(mSource);
+    mSource = nullptr;
+
+    delete mCallback;
+    delete mRemoveFromContainerFunction;
+  }
+
+  static gboolean IdleCallback(gpointer userData)
+  {
+    gboolean      retValue     = G_SOURCE_REMOVE;
+    CallbackData* callbackData = static_cast<CallbackData*>(userData);
+
+    if(callbackData->mHasReturnValue)
+    {
+      // run the function
+      bool cont = CallbackBase::ExecuteReturn<bool>(*callbackData->mCallback);
+      if(!cont)
+      {
+        // remove callback data from the container
+        CallbackBase::Execute(*callbackData->mRemoveFromContainerFunction, callbackData);
+        // will clear up the handle
+        delete callbackData;
+      }
+      else
+      {
+        retValue = G_SOURCE_CONTINUE;
+      }
+    }
+    else
+    {
+      // remove callback data from the container first in case our callback tries to modify the container
+      CallbackBase::Execute(*callbackData->mRemoveFromContainerFunction, callbackData);
+
+      // run the function
+      CallbackBase::Execute(*callbackData->mCallback);
+
+      // will clear up the handle
+      delete callbackData;
+    }
+    return retValue;
+  }
+
+  // Data
+  CallbackBase* mCallback;                             ///< call back
+  CallbackBase* mRemoveFromContainerFunction{nullptr}; ///< Called to remove the callbackdata from the callback container
+  GSource*      mSource{nullptr};                      ///< idle handle
+  bool          mExecute{true};                        ///< whether to run the callback
+  bool          mHasReturnValue{false};                ///< true if the callback function has a return value.
+};
+
+GlibCallbackManager::GlibCallbackManager()
+: mRunning(false)
+{
+}
+
+void GlibCallbackManager::Start()
+{
+  DALI_ASSERT_DEBUG(mRunning == false);
+  mRunning = true;
+}
+
+void GlibCallbackManager::Stop()
+{
+  // make sure we're not called twice
+  DALI_ASSERT_DEBUG(mRunning == true);
+
+  mRunning = false;
+
+  for(CallbackList::iterator iter = mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
+  {
+    CallbackData* data = (*iter);
+
+    delete data;
+  }
+  mCallbackContainer.clear();
+}
+
+bool GlibCallbackManager::AddIdleCallback(CallbackBase* callback, bool hasReturnValue)
+{
+  if(!mRunning)
+  {
+    return false;
+  }
+
+  CallbackData* callbackData = new CallbackData(callback, hasReturnValue);
+
+  // To inform the manager a callback has finished, we get it to call RemoveCallbackFromContainer
+  callbackData->mRemoveFromContainerFunction = MakeCallback(this, &GlibCallbackManager::RemoveCallbackFromContainer);
+
+  // add the call back to the container
+  mCallbackContainer.push_front(callbackData);
+
+  // init the callback
+  callbackData->AddIdle();
+
+  return true;
+}
+
+void GlibCallbackManager::RemoveIdleCallback(CallbackBase* callback)
+{
+  for(CallbackList::iterator it    = mCallbackContainer.begin(),
+                             endIt = mCallbackContainer.end();
+      it != endIt;
+      ++it)
+  {
+    CallbackData* data = *it;
+
+    if(data->mCallback == callback)
+    {
+      // remove callback data from the container.
+      CallbackBase::Execute(*data->mRemoveFromContainerFunction, data);
+
+      delete data;
+    }
+  }
+}
+
+bool GlibCallbackManager::ProcessIdle()
+{
+  // TBD
+  return false;
+}
+
+void GlibCallbackManager::ClearIdleCallbacks()
+{
+  // TBD
+}
+
+bool GlibCallbackManager::AddIdleEntererCallback(CallbackBase* callback)
+{
+  if(!mRunning)
+  {
+    return false;
+  }
+
+  CallbackData* callbackData = new CallbackData(callback, true);
+
+  // To inform the manager a callback has finished, we get it to call RemoveCallbackFromContainer
+  callbackData->mRemoveFromContainerFunction = MakeCallback(this, &GlibCallbackManager::RemoveCallbackFromContainer);
+
+  // add the call back to the front of the container
+  mCallbackContainer.push_front(callbackData);
+
+  // init the callback
+  callbackData->AddIdle();
+
+  return true;
+}
+
+void GlibCallbackManager::RemoveIdleEntererCallback(CallbackBase* callback)
+{
+  RemoveIdleCallback(callback);
+}
+
+void GlibCallbackManager::RemoveCallbackFromContainer(CallbackData* callbackData)
+{
+  mCallbackContainer.remove(callbackData);
+}
+
+// Creates a concrete interface for CallbackManager
+CallbackManager* CallbackManager::New()
+{
+  return new GlibCallbackManager;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/glib/callback-manager-glib.h b/dali/internal/system/glib/callback-manager-glib.h
new file mode 100644 (file)
index 0000000..de2becf
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef DALI_ADAPTOR_GLIB_CALLBACK_MANAGER_H
+#define DALI_ADAPTOR_GLIB_CALLBACK_MANAGER_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <list>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+struct CallbackData;
+
+/**
+ * @brief Glib callback manager used to install call backs in the applications main loop.
+ * The manager keeps track of all callbacks, so that if Stop() is called it can remove them.
+ */
+class GlibCallbackManager : public CallbackManager
+{
+public:
+  /**
+   * @brief constructor
+   */
+  GlibCallbackManager();
+
+  /**
+   * @brief destructor
+   */
+  virtual ~GlibCallbackManager() = default;
+
+  /**
+   * @copydoc CallbackManager::AddIdleCallback()
+   */
+  bool AddIdleCallback(CallbackBase* callback, bool hasReturnValue) override;
+
+  /**
+   * @copydoc CallbackManager::RemoveIdleCallback()
+   */
+  void RemoveIdleCallback(CallbackBase* callback) override;
+
+  /**
+   * @copydoc CallbackManager::ProcessIdle()
+   */
+  bool ProcessIdle() override;
+
+  /**
+   * @copydoc CallbackManager::ClearIdleCallbacks()
+   */
+  void ClearIdleCallbacks() override;
+
+  /**
+   * @copydoc CallbackManager::AddIdleEntererCallback()
+   */
+  bool AddIdleEntererCallback(CallbackBase* callback) override;
+
+  /**
+   * @copydoc CallbackManager::RemoveIdleEntererCallback()
+   */
+  void RemoveIdleEntererCallback(CallbackBase* callback) override;
+
+  /**
+   * @copydoc CallbackManager::Start()
+   */
+  void Start() override;
+
+  /**
+   * @copydoc CallbackManager::Stop()
+   */
+  void Stop() override;
+
+private:
+  /**
+   * @brief Removes a single call back from the container
+   * Always called from main thread
+   * @param callbackData callback data
+   */
+  void RemoveCallbackFromContainer(CallbackData* callbackData);
+
+  typedef std::list<CallbackData*> CallbackList; ///< list of callbacks installed
+
+  bool         mRunning;           ///< flag is set to true if when running
+  CallbackList mCallbackContainer; ///< container of live callbacks
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_ADAPTOR_GLIB_CALLBACK_MANAGER_H
diff --git a/dali/internal/system/glib/file-descriptor-monitor-glib.cpp b/dali/internal/system/glib/file-descriptor-monitor-glib.cpp
new file mode 100644 (file)
index 0000000..c8b7589
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/file-descriptor-monitor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <glib-unix.h>
+#include <glib.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+extern GMainContext* GetMainLoopContext();
+
+/**
+ * Using Impl to hide away framework specific members
+ */
+struct FileDescriptorMonitor::Impl
+{
+public:
+  // Constructor
+  Impl(int fileDescriptor, CallbackBase* callback, GIOCondition eventsToMonitor)
+  : mFileDescriptor(fileDescriptor),
+    mEventsToMonitor(eventsToMonitor),
+    mCallback(callback),
+    mPollSource(nullptr)
+  {
+    mPollSource = g_unix_fd_source_new(fileDescriptor, eventsToMonitor);
+    g_source_set_callback(mPollSource, reinterpret_cast<GSourceFunc>(PollCallback), this, nullptr);
+    g_source_attach(mPollSource, GetMainLoopContext());
+  }
+
+  ~Impl()
+  {
+    g_source_destroy(mPollSource);
+    g_source_unref(mPollSource);
+    mPollSource = nullptr;
+
+    delete mCallback;
+  }
+
+  static gboolean PollCallback(int fileDescriptor, GIOCondition events, gpointer userData)
+  {
+    if(userData)
+    {
+      FileDescriptorMonitor::Impl* impl = static_cast<FileDescriptorMonitor::Impl*>(userData);
+
+      // filter the events that have occured based on what we are monitoring
+      int eventType = FileDescriptorMonitor::FD_NO_EVENT;
+
+      if((impl->mEventsToMonitor & G_IO_IN) && (events & G_IO_IN))
+      {
+        eventType = FileDescriptorMonitor::FD_READABLE;
+      }
+      if((impl->mEventsToMonitor & G_IO_OUT) && (events & G_IO_OUT))
+      {
+        eventType |= FileDescriptorMonitor::FD_WRITABLE;
+      }
+
+      // if there is an event, execute the callback
+      if(eventType != FileDescriptorMonitor::FD_NO_EVENT)
+      {
+        CallbackBase::Execute(*impl->mCallback, static_cast<FileDescriptorMonitor::EventType>(eventType));
+      }
+    }
+    return G_SOURCE_CONTINUE;
+  }
+  // Data
+  int           mFileDescriptor;
+  GIOCondition  mEventsToMonitor;
+  CallbackBase* mCallback;
+  GSource*      mPollSource;
+};
+
+FileDescriptorMonitor::FileDescriptorMonitor(int fileDescriptor, CallbackBase* callback, int eventBitmask)
+{
+  if(fileDescriptor < 1)
+  {
+    DALI_ASSERT_ALWAYS(0 && "Invalid File descriptor");
+    return;
+  }
+  GIOCondition events = static_cast<GIOCondition>(0);
+  if(eventBitmask & FD_READABLE)
+  {
+    events = G_IO_IN;
+  }
+  if(eventBitmask & FD_WRITABLE)
+  {
+    events = static_cast<GIOCondition>(static_cast<int>(events) | G_IO_OUT);
+  }
+
+  DALI_ASSERT_ALWAYS(events && "Invalid FileDescriptorMonitor event type ");
+
+  // waiting for a write event on a file descriptor
+  mImpl = new Impl(fileDescriptor, callback, static_cast<GIOCondition>(events));
+}
+
+FileDescriptorMonitor::~FileDescriptorMonitor()
+{
+  delete mImpl;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/glib/timer-impl-glib.cpp b/dali/internal/system/glib/timer-impl-glib.cpp
new file mode 100644 (file)
index 0000000..3277179
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/timer-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/internal/system/common/time-service.h>
+
+// EXTERNAL INCLUDES
+#include <glib.h>
+#include <sys/time.h>
+
+namespace Dali::Internal::Adaptor
+{
+extern GMainContext* GetMainLoopContext();
+
+namespace
+{
+gboolean TimerSourceFunc(gpointer userData)
+{
+  Timer* timer = static_cast<Timer*>(userData);
+
+  bool keepRunning = timer->Tick();
+  return keepRunning ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
+}
+
+} // unnamed namespace
+
+struct Timer::Impl
+{
+  Impl(unsigned int milliSec)
+  : mInterval(milliSec)
+  {
+  }
+
+  GSource*     mTimerHandle{nullptr};
+  unsigned int mInterval{0};
+  uint32_t     mStartTimestamp{0};
+  uint32_t     mPauseTimestamp{0};
+  bool         mRunning{false};
+  bool         mRestartAfterExpiry{false}; // Restart at full interval after pause/resume/expiry
+};
+
+TimerPtr Timer::New(unsigned int milliSec)
+{
+  TimerPtr timer(new Timer(milliSec));
+  return timer;
+}
+
+Timer::Timer(unsigned int milliSec)
+: mImpl(new Impl(milliSec))
+{
+}
+
+Timer::~Timer()
+{
+  Stop();
+  delete mImpl;
+}
+
+void Timer::Start()
+{
+  if(mImpl->mRunning && mImpl->mTimerHandle)
+  {
+    Stop();
+  }
+
+  mImpl->mTimerHandle = g_timeout_source_new(mImpl->mInterval);
+  g_source_set_callback(mImpl->mTimerHandle, TimerSourceFunc, this, nullptr); // user data is this object, no need for destroy notify.
+  g_source_attach(mImpl->mTimerHandle, GetMainLoopContext());
+
+  mImpl->mRunning        = true;
+  mImpl->mStartTimestamp = TimeService::GetMilliSeconds();
+}
+
+void Timer::Stop()
+{
+  if(mImpl->mTimerHandle != nullptr)
+  {
+    g_source_destroy(mImpl->mTimerHandle);
+    g_source_unref(mImpl->mTimerHandle);
+    mImpl->mTimerHandle = nullptr;
+
+    mImpl->mStartTimestamp = 0;
+    mImpl->mPauseTimestamp = 0;
+  }
+
+  ResetTimerData();
+}
+
+void Timer::Pause()
+{
+  if(mImpl->mRunning)
+  {
+    g_source_destroy(mImpl->mTimerHandle);
+    g_source_unref(mImpl->mTimerHandle);
+    mImpl->mTimerHandle    = nullptr;
+    mImpl->mPauseTimestamp = TimeService::GetMilliSeconds();
+  }
+}
+
+void Timer::Resume()
+{
+  if(mImpl->mRunning && mImpl->mTimerHandle == nullptr)
+  {
+    uint32_t newInterval = 0;
+    uint32_t runningTime = mImpl->mPauseTimestamp - mImpl->mStartTimestamp;
+    if(mImpl->mInterval > runningTime)
+    {
+      newInterval = mImpl->mInterval - runningTime;
+    }
+
+    mImpl->mStartTimestamp = TimeService::GetMilliSeconds() - runningTime;
+    mImpl->mPauseTimestamp = 0;
+
+    mImpl->mTimerHandle = g_timeout_source_new(newInterval);
+    g_source_set_callback(mImpl->mTimerHandle, TimerSourceFunc, this, nullptr);
+    g_source_attach(mImpl->mTimerHandle, GetMainLoopContext());
+    // After next expiry, stop and restart with correct interval
+    mImpl->mRestartAfterExpiry = true;
+  }
+}
+
+void Timer::SetInterval(unsigned int interval, bool restart)
+{
+  // stop existing timer
+  Stop();
+  mImpl->mInterval = interval;
+
+  if(restart)
+  {
+    // start new tick
+    Start();
+  }
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle(this);
+
+  bool retVal(false);
+
+  // Override with new signal if used
+  if(!mTickSignal.Empty())
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if(retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true; // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  if(mImpl->mRestartAfterExpiry && mImpl->mRunning)
+  {
+    mImpl->mRestartAfterExpiry = false;
+    // Timer was resumed.
+    retVal = false;
+    ResetTimerData();
+    Start();
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+void Timer::ResetTimerData()
+{
+  mImpl->mRunning = false;
+  if(mImpl->mTimerHandle)
+  {
+    g_source_unref(mImpl->mTimerHandle);
+  }
+  mImpl->mTimerHandle = nullptr;
+}
+
+bool Timer::IsRunning() const
+{
+  return mImpl->mRunning;
+}
+
+} // namespace Dali::Internal::Adaptor
index 570d67f..8a41c87 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& messag
   switch(level)
   {
     case Dali::Integration::Log::DebugInfo:
-      format = "\e[1;34mINFO:\e[21m %s: %s\e[0m";
+      format = "\e[1;32mINFO:\e[21m %s: %s\e[0m";
       break;
     case Dali::Integration::Log::DebugWarning:
       format = "\e[1;33mWARN:\e[21m %s: %s\e[0m";
index 3ff5004..13c5618 100644 (file)
 #include <unordered_map>
 #include <vector>
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 namespace Dali
 {
 namespace Internal
@@ -440,7 +444,8 @@ struct WindowSystemX::Impl
     mXEventMonitor = new FileDescriptorMonitor(
       ConnectionNumber(mDisplay),
       MakeCallback(this, &WindowSystemX::Impl::XPollCallback),
-      (FileDescriptorMonitor::FD_READABLE | FileDescriptorMonitor::FD_WRITABLE));
+      FileDescriptorMonitor::FD_READABLE);
+    // libuv hacks: add FD_WRITABLE.
 
     InitializeAtoms();
     SetupEventHandlers();