[Tizen][AT-SPI] Associate default labels with windows 27/308327/2
authorArtur Świgoń <a.swigon@samsung.com>
Fri, 25 Nov 2022 10:13:41 +0000 (11:13 +0100)
committerArtur Świgoń <a.swigon@samsung.com>
Thu, 21 Mar 2024 09:32:30 +0000 (09:32 +0000)
Change-Id: I575f9be4d518c7b03d8bfa2419a6d1961585d5d6
(cherry picked from commit 6f1168bbac355dbd3c082d76559d68f522469172)

dali/internal/accessibility/bridge/bridge-base.cpp
dali/internal/accessibility/bridge/bridge-base.h

index 4509694..a819f25 100644 (file)
@@ -25,6 +25,7 @@
 #include <memory>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/public-api/adaptor-framework/timer.h>
 
 using namespace Dali::Accessibility;
@@ -227,28 +228,68 @@ void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
   }
 }
 
+void BridgeBase::CompressDefaultLabels()
+{
+  // Remove entries for objects which no longer exist
+  mDefaultLabels.remove_if([](const DefaultLabelType& label) {
+    return !label.first.GetBaseHandle(); // Check window's weak handle
+    // TODO: Once Accessible becomes a handle type, check its weak handle here as well
+  });
+}
+
 void BridgeBase::RegisterDefaultLabel(Accessible* object)
 {
-  if(std::find(mDefaultLabels.begin(), mDefaultLabels.end(), object) == mDefaultLabels.end())
+  CompressDefaultLabels();
+
+  Dali::WeakHandle<Dali::Window> window = GetWindow(object);
+  if(!window.GetBaseHandle()) // true also if `object` is null
+  {
+    DALI_LOG_ERROR("Cannot register default label: object does not belong to any window");
+    return;
+  }
+
+  auto it = std::find_if(mDefaultLabels.begin(), mDefaultLabels.end(), [object](const DefaultLabelType& label) {
+    return object == label.second;
+  });
+
+  if(it == mDefaultLabels.end())
+  {
+    mDefaultLabels.push_back({window, object});
+  }
+  else if(it->first != window)
+  {
+    // TODO: Tentative implementation. It is yet to be specified what should happen
+    // when the same object is re-registered as a default label for another window.
+    *it = {window, object};
+  }
+  else // it->first == window && it->second == object
   {
-    mDefaultLabels.push_back(object);
+    // Nothing to do
   }
 }
 
 void BridgeBase::UnregisterDefaultLabel(Accessible* object)
 {
-  auto it = std::find(mDefaultLabels.begin(), mDefaultLabels.end(), object);
-  if(it != mDefaultLabels.end())
-  {
-    mDefaultLabels.erase(it);
-  }
+  CompressDefaultLabels();
+
+  mDefaultLabels.remove_if([object](const DefaultLabelType& label) {
+    return object == label.second;
+  });
 }
 
 Accessible* BridgeBase::GetDefaultLabel(Accessible* root) const
 {
-  // TODO (multi-window support): Change mDefaultLabels to a collection of vectors
-  // (one per window) and select the right one based on the window that 'root' belongs to.
-  return mDefaultLabels.empty() ? root : mDefaultLabels.back();
+  Dali::WeakHandle<Dali::Window> window = GetWindow(root);
+  if(!window.GetBaseHandle())
+  {
+    return root;
+  }
+
+  auto it = std::find_if(mDefaultLabels.rbegin(), mDefaultLabels.rend(), [&window](const DefaultLabelType& label) {
+    return window == label.first;
+  });
+
+  return (it == mDefaultLabels.rend()) ? root : it->second;
 }
 
 std::string BridgeBase::StripPrefix(const std::string& path)
@@ -360,3 +401,17 @@ auto BridgeBase::CreateCacheElement(Accessible* item) -> CacheElementType
     item->GetDescription(),
     item->GetStates().GetRawData());
 }
+
+Dali::WeakHandle<Dali::Window> BridgeBase::GetWindow(Dali::Accessibility::Accessible* accessible)
+{
+  Dali::WeakHandle<Dali::Window> windowHandle;
+  Dali::Actor                    actor = accessible ? accessible->GetInternalActor() : Dali::Actor();
+
+  if(actor)
+  {
+    Dali::Window window = Dali::DevelWindow::Get(actor);
+    windowHandle        = {window};
+  }
+
+  return windowHandle;
+}
index 35e9e66..60fbb44 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/dali-adaptor-version.h>
+#include <dali/public-api/object/weak-handle.h>
 #include <dali/public-api/signals/connection-tracker.h>
 #include <memory>
 #include <tuple>
@@ -611,9 +612,13 @@ public:
   }
 
 protected:
-  mutable ApplicationAccessible                 mApplication;
-  std::vector<Dali::Accessibility::Accessible*> mDefaultLabels;
-  bool                                          mIsScreenReaderSuppressed = false;
+  // We use a weak handle in order not to keep a window alive forever if someone forgets to UnregisterDefaultLabel()
+  using DefaultLabelType  = std::pair<Dali::WeakHandle<Dali::Window>, Dali::Accessibility::Accessible*>;
+  using DefaultLabelsType = std::list<DefaultLabelType>;
+
+  mutable ApplicationAccessible mApplication;
+  DefaultLabelsType             mDefaultLabels;
+  bool                          mIsScreenReaderSuppressed = false;
 
 private:
   /**
@@ -663,6 +668,19 @@ private:
    */
   CacheElementType CreateCacheElement(Dali::Accessibility::Accessible* item);
 
+  /**
+   * @brief Removes expired elements from the default label collection.
+   */
+  void CompressDefaultLabels();
+
+  /**
+   * @brief Gets the window to which this accessible belongs (or an empty handle).
+   *
+   * @param accessible The accessible
+   * @return The window
+   */
+  static Dali::WeakHandle<Dali::Window> GetWindow(Dali::Accessibility::Accessible* accessible);
+
 protected:
   BridgeBase();
   virtual ~BridgeBase();