1 #ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
2 #define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
5 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/dali-adaptor-version.h>
24 #include <dali/public-api/object/weak-handle.h>
25 #include <dali/public-api/signals/connection-tracker.h>
30 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
31 #include <dali/devel-api/adaptor-framework/window-devel.h>
32 #include <dali/devel-api/atspi-interfaces/accessible.h>
33 #include <dali/devel-api/atspi-interfaces/application.h>
34 #include <dali/devel-api/atspi-interfaces/collection.h>
35 #include <dali/devel-api/atspi-interfaces/socket.h>
36 #include <dali/internal/accessibility/bridge/accessibility-common.h>
39 * @brief The ApplicationAccessible class is to define Accessibility Application.
41 class ApplicationAccessible : public virtual Dali::Accessibility::Accessible,
42 public virtual Dali::Accessibility::Application,
43 public virtual Dali::Accessibility::Collection,
44 public virtual Dali::Accessibility::Component,
45 public virtual Dali::Accessibility::Socket
48 Dali::Accessibility::ProxyAccessible mParent;
49 std::vector<Dali::Accessibility::Accessible*> mChildren;
51 std::string mToolkitName{"dali"};
52 bool mIsEmbedded{false};
54 std::string GetName() const override
59 std::string GetDescription() const override
64 Dali::Accessibility::Accessible* GetParent() override
69 size_t GetChildCount() const override
71 return mChildren.size();
74 std::vector<Dali::Accessibility::Accessible*> GetChildren() override
79 Dali::Accessibility::Accessible* GetChildAtIndex(size_t index) override
81 auto size = mChildren.size();
84 throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(size) + " children"};
86 return mChildren[index];
89 size_t GetIndexInParent() override
96 throw std::domain_error{"can't call GetIndexInParent on application object"};
99 Dali::Accessibility::Role GetRole() const override
101 return Dali::Accessibility::Role::APPLICATION;
104 Dali::Accessibility::States GetStates() override
106 Dali::Accessibility::States result;
108 for(auto* child : mChildren)
110 result = result | child->GetStates();
113 // The Application object should never have the SENSITIVE state
114 result[Dali::Accessibility::State::SENSITIVE] = false;
119 Dali::Accessibility::Attributes GetAttributes() const override
125 * @brief Gets the Accessible object from the window.
127 * @param[in] window The window to find
128 * @return Null if mChildren is empty, otherwise the Accessible object
129 * @note Currently, the default window would be returned when mChildren is not empty.
131 Dali::Accessibility::Accessible* GetWindowAccessible(Dali::Window window)
133 if(mChildren.empty())
138 Dali::Layer rootLayer = window.GetRootLayer();
140 // Find a child which is related to the window.
141 for(auto i = 0u; i < mChildren.size(); ++i)
143 if(rootLayer == mChildren[i]->GetInternalActor())
149 // If can't find its children, return the default window.
153 bool DoGesture(const Dali::Accessibility::GestureInfo& gestureInfo) override
158 std::vector<Dali::Accessibility::Relation> GetRelationSet() override
163 Dali::Actor GetInternalActor() const override
165 return Dali::Actor{};
168 Dali::Accessibility::Address GetAddress() const override
175 std::string GetToolkitName() const override
180 std::string GetVersion() const override
182 return std::to_string(Dali::ADAPTOR_MAJOR_VERSION) + "." + std::to_string(Dali::ADAPTOR_MINOR_VERSION);
187 Dali::Accessibility::Address Embed(Dali::Accessibility::Address plug) override
190 mParent.SetAddress(plug);
195 void Unembed(Dali::Accessibility::Address plug) override
197 if(mParent.GetAddress() == plug)
200 mParent.SetAddress({});
201 Dali::Accessibility::Bridge::GetCurrentBridge()->SetExtentsOffset(0, 0);
205 void SetOffset(std::int32_t x, std::int32_t y) override
212 Dali::Accessibility::Bridge::GetCurrentBridge()->SetExtentsOffset(x, y);
217 Dali::Rect<> GetExtents(Dali::Accessibility::CoordinateType type) const override
219 using limits = std::numeric_limits<float>;
221 float minX = limits::max();
222 float minY = limits::max();
223 float maxX = limits::min();
224 float maxY = limits::min();
226 for(Dali::Accessibility::Accessible* child : mChildren)
228 auto* component = Dali::Accessibility::Component::DownCast(child);
234 auto extents = component->GetExtents(type);
236 minX = std::min(minX, extents.x);
237 minY = std::min(minY, extents.y);
238 maxX = std::max(maxX, extents.x + extents.width);
239 maxY = std::max(maxY, extents.y + extents.height);
242 return {minX, minY, maxX - minX, maxY - minY};
245 Dali::Accessibility::ComponentLayer GetLayer() const override
247 return Dali::Accessibility::ComponentLayer::WINDOW;
250 std::int16_t GetMdiZOrder() const override
255 bool GrabFocus() override
260 double GetAlpha() const override
265 bool GrabHighlight() override
270 bool ClearHighlight() override
275 bool IsScrollable() const override
282 * @brief Enumeration for CoalescableMessages.
284 enum class CoalescableMessages
286 BOUNDS_CHANGED, ///< Bounds changed
287 SET_OFFSET, ///< Set offset
288 POST_RENDER, ///< Post render
289 STATE_CHANGED_BEGIN = 500, ///< State changed (begin of reserved range)
290 STATE_CHANGED_END = STATE_CHANGED_BEGIN + 99, ///< State changed (end of reserved range)
291 PROPERTY_CHANGED_BEGIN, ///< Property changed (begin of reserved range)
292 PROPERTY_CHANGED_END = PROPERTY_CHANGED_BEGIN + 99, ///< Property changed (end of reserved range)
295 // Custom specialization of std::hash
299 struct hash<std::pair<CoalescableMessages, Dali::Accessibility::Accessible*>>
301 size_t operator()(std::pair<CoalescableMessages, Dali::Accessibility::Accessible*> value) const
303 return (static_cast<size_t>(value.first) * 131) ^ reinterpret_cast<size_t>(value.second);
309 * @brief The BridgeBase class is basic class for Bridge functions.
311 class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker
313 std::unordered_map<std::pair<CoalescableMessages, Dali::Accessibility::Accessible*>, std::tuple<unsigned int, unsigned int, std::function<void()>>> mCoalescableMessages;
316 * @brief Removes all CoalescableMessages using Tick signal.
318 * @return False if mCoalescableMessages is empty, otherwise true.
320 bool TickCoalescableMessages();
324 * @brief Adds CoalescableMessages, Accessible, and delay time to mCoalescableMessages.
326 * @param[in] kind CoalescableMessages enum value
327 * @param[in] obj Accessible object
328 * @param[in] delay The delay time
329 * @param[in] functor The function to be called // NEED TO UPDATE!
331 void AddCoalescableMessage(CoalescableMessages kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
334 * @brief Callback when the visibility of the window is changed.
336 * @param[in] window The window to be changed
337 * @param[in] visible The visibility of the window
339 void OnWindowVisibilityChanged(Dali::Window window, bool visible);
342 * @brief Callback when the window focus is changed.
344 * @param[in] window The window whose focus is changed
345 * @param[in] focusIn Whether the focus is in/out
347 void OnWindowFocusChanged(Dali::Window window, bool focusIn);
350 * @copydoc Dali::Accessibility::Bridge::GetBusName()
352 const std::string& GetBusName() const override;
355 * @copydoc Dali::Accessibility::Bridge::AddTopLevelWindow()
357 void AddTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
360 * @copydoc Dali::Accessibility::Bridge::RemoveTopLevelWindow()
362 void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
365 * @copydoc Dali::Accessibility::Bridge::RegisterDefaultLabel()
367 void RegisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
370 * @copydoc Dali::Accessibility::Bridge::UnregisterDefaultLabel()
372 void UnregisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
375 * @copydoc Dali::Accessibility::Bridge::GetDefaultLabel()
377 Dali::Accessibility::Accessible* GetDefaultLabel(Dali::Accessibility::Accessible* root) const override;
380 * @copydoc Dali::Accessibility::Bridge::GetApplication()
382 Dali::Accessibility::Accessible* GetApplication() const override
384 return &mApplication;
388 * @brief Adds function to dbus interface.
390 template<typename SELF, typename... RET, typename... ARGS>
391 void AddFunctionToInterface(
392 DBus::DBusInterfaceDescription& desc, const std::string& funcName, DBus::ValueOrError<RET...> (SELF::*funcPtr)(ARGS...))
394 if(auto self = dynamic_cast<SELF*>(this))
395 desc.addMethod<DBus::ValueOrError<RET...>(ARGS...)>(
397 [=](ARGS... args) -> DBus::ValueOrError<RET...> {
400 return (self->*funcPtr)(std::move(args)...);
402 catch(std::domain_error& e)
404 return DBus::Error{e.what()};
410 * @brief Adds 'Get' property to dbus interface.
412 template<typename T, typename SELF>
413 void AddGetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
414 const std::string& funcName,
415 T (SELF::*funcPtr)())
417 if(auto self = dynamic_cast<SELF*>(this))
418 desc.addProperty<T>(funcName,
419 [=]() -> DBus::ValueOrError<T> {
422 return (self->*funcPtr)();
424 catch(std::domain_error& e)
426 return DBus::Error{e.what()};
433 * @brief Adds 'Set' property to dbus interface.
435 template<typename T, typename SELF>
436 void AddSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
437 const std::string& funcName,
438 void (SELF::*funcPtr)(T))
440 if(auto self = dynamic_cast<SELF*>(this))
441 desc.addProperty<T>(funcName, {}, [=](T t) -> DBus::ValueOrError<void> {
444 (self->*funcPtr)(std::move(t));
447 catch(std::domain_error& e)
449 return DBus::Error{e.what()};
455 * @brief Adds 'Set' and 'Get' properties to dbus interface.
457 template<typename T, typename T1, typename SELF>
458 void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
459 const std::string& funcName,
460 T1 (SELF::*funcPtrGet)(),
461 DBus::ValueOrError<void> (SELF::*funcPtrSet)(T))
463 if(auto self = dynamic_cast<SELF*>(this))
466 [=]() -> DBus::ValueOrError<T> {
469 return (self->*funcPtrGet)();
471 catch(std::domain_error& e)
473 return DBus::Error{e.what()};
476 [=](T t) -> DBus::ValueOrError<void> {
479 (self->*funcPtrSet)(std::move(t));
482 catch(std::domain_error& e)
484 return DBus::Error{e.what()};
490 * @brief Adds 'Get' and 'Set' properties to dbus interface.
492 template<typename T, typename T1, typename SELF>
493 void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
494 const std::string& funcName,
495 T1 (SELF::*funcPtrGet)(),
496 void (SELF::*funcPtrSet)(T))
498 if(auto self = dynamic_cast<SELF*>(this))
501 [=]() -> DBus::ValueOrError<T> {
504 return (self->*funcPtrGet)();
506 catch(std::domain_error& e)
508 return DBus::Error{e.what()};
511 [=](T t) -> DBus::ValueOrError<void> {
514 (self->*funcPtrSet)(std::move(t));
517 catch(std::domain_error& e)
519 return DBus::Error{e.what()};
525 * @brief Gets the string of the path excluding the specified prefix.
527 * @param path The path to get
528 * @return The string stripped of the specific prefix
530 static std::string StripPrefix(const std::string& path);
533 * @brief Finds the Accessible object according to the path.
535 * @param[in] path The path for Accessible object
536 * @return The Accessible object corresponding to the path
538 Dali::Accessibility::Accessible* Find(const std::string& path) const;
541 * @brief Finds the Accessible object with the given address.
543 * @param[in] ptr The unique Address of the object
544 * @return The Accessible object corresponding to the path
546 Dali::Accessibility::Accessible* Find(const Dali::Accessibility::Address& ptr) const;
549 * @brief Returns the target object of the currently executed DBus method call.
551 * @return The Accessible object
552 * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
553 * because DBus handles the invocation target separately from the method arguments.
554 * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
555 * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
557 Dali::Accessibility::Accessible* FindCurrentObject() const;
560 * @brief Returns the target object of the currently executed DBus method call.
562 * This method tries to downcast the return value of FindCurrentObject() to the requested type,
563 * issuing an error reply to the DBus caller if the requested type is not implemented. Whether
564 * a given type is implemented is decided based on the return value of Accessible::GetInterfaces()
565 * for the current object.
567 * @tparam I The requested AT-SPI interface
568 * @return The Accessible object (cast to a more derived type)
570 * @see FindCurrentObject()
571 * @see Dali::Accessibility::AtspiInterface
572 * @see Dali::Accessibility::AtspiInterfaceType
573 * @see Dali::Accessibility::Accessible::GetInterfaces()
575 template<Dali::Accessibility::AtspiInterface I>
576 auto* FindCurrentObjectWithInterface() const
578 using Type = Dali::Accessibility::AtspiInterfaceType<I>;
581 auto* currentObject = FindCurrentObject();
582 DALI_ASSERT_DEBUG(currentObject); // FindCurrentObject() throws domain_error
584 if(!(result = Dali::Accessibility::Accessible::DownCast<I>(currentObject)))
588 s << "Object " << currentObject->GetAddress().ToString();
589 s << " does not implement ";
590 s << Dali::Accessibility::Accessible::GetInterfaceName(I);
592 throw std::domain_error{s.str()};
599 * @copydoc Dali::Accessibility::Bridge::FindByPath()
601 Dali::Accessibility::Accessible* FindByPath(const std::string& name) const override;
604 * @copydoc Dali::Accessibility::Bridge::SetApplicationName()
606 void SetApplicationName(std::string name) override
608 mApplication.mName = std::move(name);
612 * @copydoc Dali::Accessibility::Bridge::SetToolkitName()
614 void SetToolkitName(std::string_view toolkitName) override
616 mApplication.mToolkitName = std::string{toolkitName};
620 // We use a weak handle in order not to keep a window alive forever if someone forgets to UnregisterDefaultLabel()
621 using DefaultLabelType = std::pair<Dali::WeakHandle<Dali::Window>, Dali::Accessibility::Accessible*>;
622 using DefaultLabelsType = std::list<DefaultLabelType>;
624 mutable ApplicationAccessible mApplication;
625 DefaultLabelsType mDefaultLabels;
626 bool mIsScreenReaderSuppressed = false;
631 * @param[in] id An ID (integer value)
636 * @brief Gets the ID.
637 * @return The ID to be set
642 * @brief Update registered events.
644 void UpdateRegisteredEvents();
646 using CacheElementType = std::tuple<
647 Dali::Accessibility::Address,
648 Dali::Accessibility::Address,
649 Dali::Accessibility::Address,
650 std::vector<Dali::Accessibility::Address>,
651 std::vector<std::string>,
653 Dali::Accessibility::Role,
655 std::array<uint32_t, 2>>;
658 * @brief Gets Items // NEED TO UPDATE!
662 DBus::ValueOrError<std::vector<CacheElementType>> GetItems();
665 * @brief Creates CacheElement.
667 * CreateCacheElement method works for GetItems which is a part of ATSPI protocol.
668 * ATSPI client library (libatspi from at-spi2-core) depending on cacheing policy configuration uses GetItems
669 * to pre-load entire accessible tree from application to its own cache in single dbus call.
670 * Otherwise the particular nodes in a tree are cached lazily when client library tries to access them.
671 * @param item Accessible to get information
672 * @return The elements to be cached
674 CacheElementType CreateCacheElement(Dali::Accessibility::Accessible* item);
677 * @brief Removes expired elements from the default label collection.
679 void CompressDefaultLabels();
682 * @brief Gets the window to which this accessible belongs (or an empty handle).
684 * @param accessible The accessible
687 static Dali::WeakHandle<Dali::Window> GetWindow(Dali::Accessibility::Accessible* accessible);
691 virtual ~BridgeBase();
694 * @copydoc Dali::Accessibility::Bridge::ForceUp()
696 ForceUpResult ForceUp() override;
699 * @copydoc Dali::Accessibility::Bridge::ForceDown()
701 void ForceDown() override;
703 DBus::DBusServer mDbusServer;
704 DBusWrapper::ConnectionPtr mConnectionPtr;
706 DBus::DBusClient mRegistry;
707 bool IsBoundsChangedEventAllowed{false};
710 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H