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/signals/connection-tracker.h>
28 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
29 #include <dali/devel-api/adaptor-framework/window-devel.h>
30 #include <dali/devel-api/atspi-interfaces/accessible.h>
31 #include <dali/devel-api/atspi-interfaces/application.h>
32 #include <dali/devel-api/atspi-interfaces/collection.h>
33 #include <dali/devel-api/atspi-interfaces/socket.h>
34 #include <dali/internal/accessibility/bridge/accessibility-common.h>
37 * @brief The ApplicationAccessible class is to define Accessibility Application.
39 class ApplicationAccessible : public virtual Dali::Accessibility::Accessible,
40 public virtual Dali::Accessibility::Application,
41 public virtual Dali::Accessibility::Collection,
42 public virtual Dali::Accessibility::Socket
45 Dali::Accessibility::ProxyAccessible mParent;
46 std::vector<Dali::Accessibility::Accessible*> mChildren;
48 std::string mToolkitName{"dali"};
49 bool mIsEmbedded{false};
51 std::string GetName() const override
56 std::string GetDescription() const override
61 Dali::Accessibility::Accessible* GetParent() override
66 size_t GetChildCount() const override
68 return mChildren.size();
71 std::vector<Dali::Accessibility::Accessible*> GetChildren() override
76 Dali::Accessibility::Accessible* GetChildAtIndex(size_t index) override
78 auto size = mChildren.size();
81 throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(size) + " children"};
83 return mChildren[index];
86 size_t GetIndexInParent() override
93 throw std::domain_error{"can't call GetIndexInParent on application object"};
96 Dali::Accessibility::Role GetRole() const override
98 return Dali::Accessibility::Role::APPLICATION;
101 Dali::Accessibility::States GetStates() override
106 Dali::Accessibility::Attributes GetAttributes() const override
112 * @brief Gets the Accessible object from the window.
114 * @param[in] window The window to find
115 * @return Null if mChildren is empty, otherwise the Accessible object
116 * @note Currently, the default window would be returned when mChildren is not empty.
118 Dali::Accessibility::Accessible* GetWindowAccessible(Dali::Window window)
120 if(mChildren.empty())
125 Dali::Layer rootLayer = window.GetRootLayer();
127 // Find a child which is related to the window.
128 for(auto i = 0u; i < mChildren.size(); ++i)
130 if(rootLayer == mChildren[i]->GetInternalActor())
136 // If can't find its children, return the default window.
140 bool DoGesture(const Dali::Accessibility::GestureInfo& gestureInfo) override
145 std::vector<Dali::Accessibility::Relation> GetRelationSet() override
150 Dali::Actor GetInternalActor() override
152 return Dali::Actor{};
155 Dali::Accessibility::Address GetAddress() const override
160 std::string GetToolkitName() const override
165 std::string GetVersion() const override
167 return std::to_string(Dali::ADAPTOR_MAJOR_VERSION) + "." + std::to_string(Dali::ADAPTOR_MINOR_VERSION);
170 Dali::Accessibility::Address Embed(Dali::Accessibility::Address plug) override
173 mParent.SetAddress(plug);
178 void Unembed(Dali::Accessibility::Address plug) override
180 if(mParent.GetAddress() == plug)
183 mParent.SetAddress({});
189 * @brief Enumeration for FilteredEvents.
191 enum class FilteredEvents
193 BOUNDS_CHANGED ///< Bounds changed
196 // Custom specialization of std::hash
200 struct hash<std::pair<FilteredEvents, Dali::Accessibility::Accessible*>>
202 size_t operator()(std::pair<FilteredEvents, Dali::Accessibility::Accessible*> value) const
204 return (static_cast<size_t>(value.first) * 131) ^ reinterpret_cast<size_t>(value.second);
210 * @brief The BridgeBase class is basic class for Bridge functions.
212 class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker
214 std::unordered_map<std::pair<FilteredEvents, Dali::Accessibility::Accessible*>, std::pair<unsigned int, std::function<void()>>> mFilteredEvents;
217 * @brief Removes all FilteredEvents using Tick signal.
219 * @return False if mFilteredEvents is empty, otherwise true.
221 bool TickFilteredEvents();
225 * @brief Adds FilteredEvents, Accessible, and delay time to mFilteredEvents.
227 * @param[in] kind FilteredEvents enum value
228 * @param[in] obj Accessible object
229 * @param[in] delay The delay time
230 * @param[in] functor The function to be called // NEED TO UPDATE!
232 void AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
235 * @brief Callback when the visibility of the window is changed.
237 * @param[in] window The window to be changed
238 * @param[in] visible The visibility of the window
240 void OnWindowVisibilityChanged(Dali::Window window, bool visible);
243 * @brief Callback when the window focus is changed.
245 * @param[in] window The window whose focus is changed
246 * @param[in] focusIn Whether the focus is in/out
248 void OnWindowFocusChanged(Dali::Window window, bool focusIn);
251 * @copydoc Dali::Accessibility::Bridge::GetBusName()
253 const std::string& GetBusName() const override;
256 * @copydoc Dali::Accessibility::Bridge::AddTopLevelWindow()
258 void AddTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
261 * @copydoc Dali::Accessibility::Bridge::RemoveTopLevelWindow()
263 void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
266 * @copydoc Dali::Accessibility::Bridge::RegisterDefaultLabel()
268 void RegisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
271 * @copydoc Dali::Accessibility::Bridge::UnregisterDefaultLabel()
273 void UnregisterDefaultLabel(Dali::Accessibility::Accessible* object) override;
276 * @copydoc Dali::Accessibility::Bridge::GetDefaultLabel()
278 Dali::Accessibility::Accessible* GetDefaultLabel() const override
280 return mDefaultLabels.empty() ? nullptr : mDefaultLabels.back();
284 * @copydoc Dali::Accessibility::Bridge::GetApplication()
286 Dali::Accessibility::Accessible* GetApplication() const override
288 return &mApplication;
292 * @brief Adds function to dbus interface.
294 template<typename SELF, typename... RET, typename... ARGS>
295 void AddFunctionToInterface(
296 DBus::DBusInterfaceDescription& desc, const std::string& funcName, DBus::ValueOrError<RET...> (SELF::*funcPtr)(ARGS...))
298 if(auto self = dynamic_cast<SELF*>(this))
299 desc.addMethod<DBus::ValueOrError<RET...>(ARGS...)>(
301 [=](ARGS... args) -> DBus::ValueOrError<RET...> {
304 return (self->*funcPtr)(std::move(args)...);
306 catch(std::domain_error& e)
308 return DBus::Error{e.what()};
314 * @brief Adds 'Get' property to dbus interface.
316 template<typename T, typename SELF>
317 void AddGetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
318 const std::string& funcName,
319 T (SELF::*funcPtr)())
321 if(auto self = dynamic_cast<SELF*>(this))
322 desc.addProperty<T>(funcName,
323 [=]() -> DBus::ValueOrError<T> {
326 return (self->*funcPtr)();
328 catch(std::domain_error& e)
330 return DBus::Error{e.what()};
337 * @brief Adds 'Set' property to dbus interface.
339 template<typename T, typename SELF>
340 void AddSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
341 const std::string& funcName,
342 void (SELF::*funcPtr)(T))
344 if(auto self = dynamic_cast<SELF*>(this))
345 desc.addProperty<T>(funcName, {}, [=](T t) -> DBus::ValueOrError<void> {
348 (self->*funcPtr)(std::move(t));
351 catch(std::domain_error& e)
353 return DBus::Error{e.what()};
359 * @brief Adds 'Set' and 'Get' properties to dbus interface.
361 template<typename T, typename T1, typename SELF>
362 void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
363 const std::string& funcName,
364 T1 (SELF::*funcPtrGet)(),
365 DBus::ValueOrError<void> (SELF::*funcPtrSet)(T))
367 if(auto self = dynamic_cast<SELF*>(this))
370 [=]() -> DBus::ValueOrError<T> {
373 return (self->*funcPtrGet)();
375 catch(std::domain_error& e)
377 return DBus::Error{e.what()};
380 [=](T t) -> DBus::ValueOrError<void> {
383 (self->*funcPtrSet)(std::move(t));
386 catch(std::domain_error& e)
388 return DBus::Error{e.what()};
394 * @brief Adds 'Get' and 'Set' properties to dbus interface.
396 template<typename T, typename T1, typename SELF>
397 void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
398 const std::string& funcName,
399 T1 (SELF::*funcPtrGet)(),
400 void (SELF::*funcPtrSet)(T))
402 if(auto self = dynamic_cast<SELF*>(this))
405 [=]() -> DBus::ValueOrError<T> {
408 return (self->*funcPtrGet)();
410 catch(std::domain_error& e)
412 return DBus::Error{e.what()};
415 [=](T t) -> DBus::ValueOrError<void> {
418 (self->*funcPtrSet)(std::move(t));
421 catch(std::domain_error& e)
423 return DBus::Error{e.what()};
429 * @brief Gets the string of the path excluding the specified prefix.
431 * @param path The path to get
432 * @return The string stripped of the specific prefix
434 static std::string StripPrefix(const std::string& path);
437 * @brief Finds the Accessible object according to the path.
439 * @param[in] path The path for Accessible object
440 * @return The Accessible object corresponding to the path
442 Dali::Accessibility::Accessible* Find(const std::string& path) const;
445 * @brief Finds the Accessible object with the given address.
447 * @param[in] ptr The unique Address of the object
448 * @return The Accessible object corresponding to the path
450 Dali::Accessibility::Accessible* Find(const Dali::Accessibility::Address& ptr) const;
453 * @brief Returns the target object of the currently executed DBus method call.
455 * @return The Accessible object
456 * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
457 * because DBus handles the invocation target separately from the method arguments.
458 * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
459 * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
461 Dali::Accessibility::Accessible* FindCurrentObject() const;
464 * @brief Returns the target object of the currently executed DBus method call.
466 * This method tries to downcast the return value of FindCurrentObject() to the requested type,
467 * issuing an error reply to the DBus caller if the requested type is not implemented. Whether
468 * a given type is implemented is decided based on the return value of Accessible::GetInterfaces()
469 * for the current object.
471 * @tparam I The requested AT-SPI interface
472 * @return The Accessible object (cast to a more derived type)
474 * @see FindCurrentObject()
475 * @see Dali::Accessibility::AtspiInterface
476 * @see Dali::Accessibility::AtspiInterfaceType
477 * @see Dali::Accessibility::Accessible::GetInterfaces()
479 template<Dali::Accessibility::AtspiInterface I>
480 auto* FindCurrentObjectWithInterface() const
482 using Type = Dali::Accessibility::AtspiInterfaceType<I>;
485 auto* currentObject = FindCurrentObject();
486 DALI_ASSERT_DEBUG(currentObject); // FindCurrentObject() throws domain_error
488 if(!(result = Dali::Accessibility::Accessible::DownCast<I>(currentObject)))
492 s << "Object " << currentObject->GetAddress().ToString();
493 s << " does not implement ";
494 s << Dali::Accessibility::Accessible::GetInterfaceName(I);
496 throw std::domain_error{s.str()};
503 * @copydoc Dali::Accessibility::Bridge::FindByPath()
505 Dali::Accessibility::Accessible* FindByPath(const std::string& name) const override;
508 * @copydoc Dali::Accessibility::Bridge::SetApplicationName()
510 void SetApplicationName(std::string name) override
512 mApplication.mName = std::move(name);
516 * @copydoc Dali::Accessibility::Bridge::SetToolkitName()
518 void SetToolkitName(std::string_view toolkitName) override
520 mApplication.mToolkitName = std::string{toolkitName};
524 mutable ApplicationAccessible mApplication;
525 std::vector<Dali::Accessibility::Accessible*> mDefaultLabels;
526 bool mIsScreenReaderSuppressed = false;
531 * @param[in] id An ID (integer value)
536 * @brief Gets the ID.
537 * @return The ID to be set
542 * @brief Update registered events.
544 void UpdateRegisteredEvents();
546 using CacheElementType = std::tuple<
547 Dali::Accessibility::Address,
548 Dali::Accessibility::Address,
549 Dali::Accessibility::Address,
550 std::vector<Dali::Accessibility::Address>,
551 std::vector<std::string>,
553 Dali::Accessibility::Role,
555 std::array<uint32_t, 2>>;
558 * @brief Gets Items // NEED TO UPDATE!
562 DBus::ValueOrError<std::vector<CacheElementType>> GetItems();
565 * @brief Creates CacheElement.
567 * CreateCacheElement method works for GetItems which is a part of ATSPI protocol.
568 * ATSPI client library (libatspi from at-spi2-core) depending on cacheing policy configuration uses GetItems
569 * to pre-load entire accessible tree from application to its own cache in single dbus call.
570 * Otherwise the particular nodes in a tree are cached lazily when client library tries to access them.
571 * @param item Accessible to get information
572 * @return The elements to be cached
574 CacheElementType CreateCacheElement(Dali::Accessibility::Accessible* item);
578 virtual ~BridgeBase();
581 * @copydoc Dali::Accessibility::Bridge::ForceUp()
583 ForceUpResult ForceUp() override;
586 * @copydoc Dali::Accessibility::Bridge::ForceDown()
588 void ForceDown() override;
590 DBus::DBusServer mDbusServer;
591 DBusWrapper::ConnectionPtr mConnectionPtr;
593 DBus::DBusClient mRegistry;
594 bool IsBoundsChangedEventAllowed{false};
597 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H