/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
// EXTERNAL INCLUDES
#include <iostream>
#include <string>
+#include <string_view>
+#include <unordered_map>
using namespace Dali::Accessibility;
+namespace
+{
+inline std::string GetAccessiblePath(Accessible* accessible)
+{
+ auto address = accessible->GetAddress();
+ return address ? ATSPI_PREFIX_PATH + address.GetPath() : ATSPI_NULL_PATH;
+}
+} // namespace
+
BridgeObject::BridgeObject()
{
}
void BridgeObject::RegisterInterfaces()
{
- // DBus::DBusInterfaceDescription desc{ AtspiDbusInterfaceEventObject };
- // stateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
- // dbusServer.addInterface("/", desc, true);
+ // DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT)};
+ // mStateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
+ // mDbusServer.addInterface("/", desc, true);
}
void BridgeObject::EmitActiveDescendantChanged(Accessible* obj, Accessible* child)
{
- if(!IsUp()) return;
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::ACTIVE_DESCENDANT_CHANGED] || child->IsHidden())
+ {
+ return;
+ }
+
auto index = child->GetIndexInParent();
- auto addr = obj->GetAddress();
- const auto prefixPath = "/org/a11y/atspi/accessible/";
- const auto nullPath = "/org/a11y/atspi/null";
- std::string p;
- if(addr)
- p = prefixPath + addr.GetPath();
- else
- p = nullPath;
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<Address>, Address>(
- p,
- AtspiDbusInterfaceEventObject,
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<Address>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
"ActiveDescendantChanged",
"",
index,
{"", "root"});
}
-void BridgeObject::Emit(Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent ev)
+void BridgeObject::Emit(std::shared_ptr<Accessible> obj, ObjectPropertyChangeEvent event)
{
- if(!IsUp()) return;
- const char* name = nullptr;
- switch(ev)
+ static const std::unordered_map<ObjectPropertyChangeEvent, std::string_view> eventMap{
+ {ObjectPropertyChangeEvent::NAME, "accessible-name"},
+ {ObjectPropertyChangeEvent::DESCRIPTION, "accessible-description"},
+ {ObjectPropertyChangeEvent::VALUE, "accessible-value"},
+ {ObjectPropertyChangeEvent::PARENT, "accessible-parent"},
+ {ObjectPropertyChangeEvent::ROLE, "accessible-role"},
+ };
+
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::PROPERTY_CHANGED])
{
- case ObjectPropertyChangeEvent::NAME:
- {
- name = "accessible-name";
- break;
- }
- case ObjectPropertyChangeEvent::DESCRIPTION:
- {
- name = "accessible-description";
- break;
- }
- case ObjectPropertyChangeEvent::VALUE:
- {
- name = "accessible-value";
- break;
- }
- case ObjectPropertyChangeEvent::PARENT:
- {
- name = "accessible-parent";
- break;
- }
- case ObjectPropertyChangeEvent::ROLE:
- {
- name = "accessible-role";
- break;
- }
+ return;
}
- if(name)
+
+ auto eventName = eventMap.find(event);
+
+ if(eventName != eventMap.end())
{
- auto addr = obj->GetAddress();
- std::string p;
- if(addr)
- p = ATSPI_PREFIX_PATH + addr.GetPath();
- else
- p = ATSPI_NULL_PATH;
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
- p,
- AtspiDbusInterfaceEventObject,
- "PropertyChange",
- name,
- 0,
- 0,
- {0},
- {"", "root"});
+ AddCoalescableMessage(static_cast<CoalescableMessages>(static_cast<int>(CoalescableMessages::PROPERTY_CHANGED_BEGIN) + static_cast<int>(event)), obj.get(), 1.0f, [=, weakObj = std::weak_ptr<Accessible>(obj)]() {
+ if(auto accessible = weakObj.lock())
+ {
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(accessible.get()),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
+ "PropertyChange",
+ std::string{eventName->second},
+ 0,
+ 0,
+ {0},
+ {"", "root"});
+ }
+ });
}
}
-void BridgeObject::Emit(Accessible* obj, WindowEvent we, unsigned int detail1)
+void BridgeObject::Emit(Accessible* obj, WindowEvent event, unsigned int detail)
{
- if(!IsUp()) return;
- const char* name = nullptr;
- switch(we)
+ static const std::unordered_map<WindowEvent, std::string_view> eventMap{
+ {WindowEvent::PROPERTY_CHANGE, "PropertyChange"},
+ {WindowEvent::MINIMIZE, "Minimize"},
+ {WindowEvent::MAXIMIZE, "Maximize"},
+ {WindowEvent::RESTORE, "Restore"},
+ {WindowEvent::CLOSE, "Close"},
+ {WindowEvent::CREATE, "Create"},
+ {WindowEvent::REPARENT, "Reparent"},
+ {WindowEvent::DESKTOP_CREATE, "DesktopCreate"},
+ {WindowEvent::DESKTOP_DESTROY, "DesktopDestroy"},
+ {WindowEvent::DESTROY, "Destroy"},
+ {WindowEvent::ACTIVATE, "Activate"},
+ {WindowEvent::DEACTIVATE, "Deactivate"},
+ {WindowEvent::RAISE, "Raise"},
+ {WindowEvent::LOWER, "Lower"},
+ {WindowEvent::MOVE, "Move"},
+ {WindowEvent::RESIZE, "Resize"},
+ {WindowEvent::SHADE, "Shade"},
+ {WindowEvent::UU_SHADE, "uUshade"},
+ {WindowEvent::RESTYLE, "Restyle"},
+ {WindowEvent::POST_RENDER, "PostRender"},
+ };
+
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::WINDOW_CHANGED])
{
- case WindowEvent::PROPERTY_CHANGE:
- {
- name = "PropertyChange";
- break;
- }
- case WindowEvent::MINIMIZE:
- {
- name = "Minimize";
- break;
- }
- case WindowEvent::MAXIMIZE:
- {
- name = "Maximize";
- break;
- }
- case WindowEvent::RESTORE:
- {
- name = "Restore";
- break;
- }
- case WindowEvent::CLOSE:
- {
- name = "Close";
- break;
- }
- case WindowEvent::CREATE:
- {
- name = "Create";
- break;
- }
- case WindowEvent::REPARENT:
- {
- name = "Reparent";
- break;
- }
- case WindowEvent::DESKTOP_CREATE:
- {
- name = "DesktopCreate";
- break;
- }
- case WindowEvent::DESKTOP_DESTROY:
- {
- name = "DesktopDestroy";
- break;
- }
- case WindowEvent::DESTROY:
- {
- name = "Destroy";
- break;
- }
- case WindowEvent::ACTIVATE:
- {
- name = "Activate";
- break;
- }
- case WindowEvent::DEACTIVATE:
- {
- name = "Deactivate";
- break;
- }
- case WindowEvent::RAISE:
- {
- name = "Raise";
- break;
- }
- case WindowEvent::LOWER:
- {
- name = "Lower";
- break;
- }
- case WindowEvent::MOVE:
- {
- name = "Move";
- break;
- }
- case WindowEvent::RESIZE:
- {
- name = "Resize";
- break;
- }
- case WindowEvent::SHADE:
- {
- name = "Shade";
- break;
- }
- case WindowEvent::UU_SHADE:
- {
- name = "uUshade";
- break;
- }
- case WindowEvent::RESTYLE:
- {
- name = "Restyle";
- break;
- }
+ return;
}
- if(name)
+
+ auto eventName = eventMap.find(event);
+
+ if(eventName != eventMap.end())
{
- auto addr = obj->GetAddress();
- std::string p;
- if(addr)
- p = ATSPI_PREFIX_PATH + addr.GetPath();
- else
- p = ATSPI_NULL_PATH;
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
- p,
- AtspiDbusInterfaceEventWindow,
- name,
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_WINDOW),
+ std::string{eventName->second},
"",
- detail1,
+ detail,
0,
{0},
{"", "root"});
}
}
-void BridgeObject::EmitStateChanged(Accessible* obj, State state, int newValue1, int newValue2)
+void BridgeObject::EmitStateChanged(std::shared_ptr<Accessible> obj, State state, int newValue, int reserved)
{
- if(!IsUp()) return;
- const char* stateName = nullptr;
- switch(state)
+ static const std::unordered_map<State, std::string_view> stateMap{
+ {State::INVALID, "invalid"},
+ {State::ACTIVE, "active"},
+ {State::ARMED, "armed"},
+ {State::BUSY, "busy"},
+ {State::CHECKED, "checked"},
+ {State::COLLAPSED, "collapsed"},
+ {State::DEFUNCT, "defunct"},
+ {State::EDITABLE, "editable"},
+ {State::ENABLED, "enabled"},
+ {State::EXPANDABLE, "expandable"},
+ {State::EXPANDED, "expanded"},
+ {State::FOCUSABLE, "focusable"},
+ {State::FOCUSED, "focused"},
+ {State::HAS_TOOLTIP, "has-tooltip"},
+ {State::HORIZONTAL, "horizontal"},
+ {State::ICONIFIED, "iconified"},
+ {State::MODAL, "modal"},
+ {State::MULTI_LINE, "multi-line"},
+ {State::MULTI_SELECTABLE, "multiselectable"},
+ {State::OPAQUE, "opaque"},
+ {State::PRESSED, "pressed"},
+ {State::RESIZEABLE, "resizable"},
+ {State::SELECTABLE, "selectable"},
+ {State::SELECTED, "selected"},
+ {State::SENSITIVE, "sensitive"},
+ {State::SHOWING, "showing"},
+ {State::SINGLE_LINE, "single-line"},
+ {State::STALE, "stale"},
+ {State::TRANSIENT, "transient"},
+ {State::VERTICAL, "vertical"},
+ {State::VISIBLE, "visible"},
+ {State::MANAGES_DESCENDANTS, "manages-descendants"},
+ {State::INDETERMINATE, "indeterminate"},
+ {State::REQUIRED, "required"},
+ {State::TRUNCATED, "truncated"},
+ {State::ANIMATED, "animated"},
+ {State::INVALID_ENTRY, "invalid-entry"},
+ {State::SUPPORTS_AUTOCOMPLETION, "supports-autocompletion"},
+ {State::SELECTABLE_TEXT, "selectable-text"},
+ {State::IS_DEFAULT, "is-default"},
+ {State::VISITED, "visited"},
+ {State::CHECKABLE, "checkable"},
+ {State::HAS_POPUP, "has-popup"},
+ {State::READ_ONLY, "read-only"},
+ {State::HIGHLIGHTED, "highlighted"},
+ {State::HIGHLIGHTABLE, "highlightable"},
+ };
+
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::STATE_CHANGED]) // separate ?
{
- case State::INVALID:
- {
- stateName = "invalid";
- break;
- }
- case State::ACTIVE:
- {
- stateName = "active";
- break;
- }
- case State::ARMED:
- {
- stateName = "armed";
- break;
- }
- case State::BUSY:
- {
- stateName = "busy";
- break;
- }
- case State::CHECKED:
- {
- stateName = "checked";
- break;
- }
- case State::COLLAPSED:
- {
- stateName = "collapsed";
- break;
- }
- case State::DEFUNCT:
- {
- stateName = "defunct";
- break;
- }
- case State::EDITABLE:
- {
- stateName = "editable";
- break;
- }
- case State::ENABLED:
- {
- stateName = "enabled";
- break;
- }
- case State::EXPANDABLE:
- {
- stateName = "expandable";
- break;
- }
- case State::EXPANDED:
- {
- stateName = "expanded";
- break;
- }
- case State::FOCUSABLE:
- {
- stateName = "focusable";
- break;
- }
- case State::FOCUSED:
- {
- stateName = "focused";
- break;
- }
- case State::HAS_TOOLTIP:
- {
- stateName = "has-tooltip";
- break;
- }
- case State::HORIZONTAL:
- {
- stateName = "horizontal";
- break;
- }
- case State::ICONIFIED:
- {
- stateName = "iconified";
- break;
- }
- case State::MODAL:
- {
- stateName = "modal";
- break;
- }
- case State::MULTI_LINE:
- {
- stateName = "multi-line";
- break;
- }
- case State::MULTI_SELECTABLE:
- {
- stateName = "multiselectable";
- break;
- }
- case State::OPAQUE:
- {
- stateName = "opaque";
- break;
- }
- case State::PRESSED:
- {
- stateName = "pressed";
- break;
- }
- case State::RESIZEABLE:
- {
- stateName = "resizable";
- break;
- }
- case State::SELECTABLE:
- {
- stateName = "selectable";
- break;
- }
- case State::SELECTED:
- {
- stateName = "selected";
- break;
- }
- case State::SENSITIVE:
- {
- stateName = "sensitive";
- break;
- }
- case State::SHOWING:
- {
- stateName = "showing";
- break;
- }
- case State::SINGLE_LINE:
- {
- stateName = "single-line";
- break;
- }
- case State::STALE:
- {
- stateName = "stale";
- break;
- }
- case State::TRANSIENT:
- {
- stateName = "transient";
- break;
- }
- case State::VERTICAL:
- {
- stateName = "vertical";
- break;
- }
- case State::VISIBLE:
- {
- stateName = "visible";
- break;
- }
- case State::MANAGES_DESCENDANTS:
- {
- stateName = "manages-descendants";
- break;
- }
- case State::INDETERMINATE:
- {
- stateName = "indeterminate";
- break;
- }
- case State::REQUIRED:
- {
- stateName = "required";
- break;
- }
- case State::TRUNCATED:
- {
- stateName = "truncated";
- break;
- }
- case State::ANIMATED:
- {
- stateName = "animated";
- break;
- }
- case State::INVALID_ENTRY:
- {
- stateName = "invalid-entry";
- break;
- }
- case State::SUPPORTS_AUTOCOMPLETION:
- {
- stateName = "supports-autocompletion";
- break;
- }
- case State::SELECTABLE_TEXT:
- {
- stateName = "selectable-text";
- break;
- }
- case State::IS_DEFAULT:
- {
- stateName = "is-default";
- break;
- }
- case State::VISITED:
- {
- stateName = "visited";
- break;
- }
- case State::CHECKABLE:
- {
- stateName = "checkable";
- break;
- }
- case State::HAS_POPUP:
- {
- stateName = "has-popup";
- break;
- }
- case State::READ_ONLY:
- {
- stateName = "read-only";
- break;
- }
- case State::HIGHLIGHTED:
- {
- stateName = "highlighted";
- break;
- }
- case State::HIGHLIGHTABLE:
- {
- stateName = "highlightable";
- break;
- }
- case State::MAX_COUNT:
- {
- break;
- }
+ return;
}
- if(stateName)
+
+ auto stateName = stateMap.find(state);
+
+ if(stateName != stateMap.end())
{
- auto addr = obj->GetAddress();
- std::string p;
- if(addr)
- p = ATSPI_PREFIX_PATH + addr.GetPath();
- else
- p = ATSPI_NULL_PATH;
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
- p,
- AtspiDbusInterfaceEventObject,
- "StateChanged",
- stateName,
- newValue1,
- newValue2,
- {0},
- {"", "root"});
+ AddCoalescableMessage(static_cast<CoalescableMessages>(static_cast<int>(CoalescableMessages::STATE_CHANGED_BEGIN) + static_cast<int>(state)), obj.get(), 1.0f, [=, weakObj = std::weak_ptr<Accessible>(obj)]() {
+ if(auto accessible = weakObj.lock())
+ {
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(accessible.get()),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
+ "StateChanged",
+ std::string{stateName->second},
+ newValue,
+ reserved,
+ {0},
+ {"", "root"});
+ }
+ });
}
}
-void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
+void BridgeObject::EmitBoundsChanged(std::shared_ptr<Accessible> obj, Dali::Rect<> rect)
{
- if(!allowObjectBoundsChangedEvent) return;
-
- auto addr = obj->GetAddress();
- const auto prefixPath = "/org/a11y/atspi/accessible/";
- const auto nullPath = "/org/a11y/atspi/null";
- std::string p;
- if(addr)
- p = prefixPath + addr.GetPath();
- else
- p = nullPath;
- DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> > tmp{
- std::tuple<int32_t, int32_t, int32_t, int32_t>{rect.x, rect.y, rect.width, rect.height}};
- addFilteredEvent(FilteredEvents::boundsChanged, obj, 1.0f, [=]() {
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> >, Address>(
- p,
- AtspiDbusInterfaceEventObject,
- "BoundsChanged",
- "",
- 0,
- 0,
- tmp,
- {"", "root"});
+ if(!IsUp() || !IsBoundsChangedEventAllowed || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::BOUNDS_CHANGED])
+ {
+ return;
+ }
+
+ AddCoalescableMessage(CoalescableMessages::BOUNDS_CHANGED, obj.get(), 1.0f, [=, weakObj = std::weak_ptr<Accessible>(obj), rect = std::move(rect)]() {
+ if(auto accessible = weakObj.lock())
+ {
+ DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> > tmp{
+ std::tuple<int32_t, int32_t, int32_t, int32_t>{rect.x, rect.y, rect.width, rect.height}};
+
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> >, Address>(
+ GetAccessiblePath(accessible.get()),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
+ "BoundsChanged",
+ "",
+ 0,
+ 0,
+ tmp,
+ {"", "root"});
+ }
});
}
-void BridgeObject::EmitCaretMoved(Accessible* obj, unsigned int cursorPosition)
+void BridgeObject::EmitPostRender(std::shared_ptr<Accessible> obj)
{
- auto addr = obj->GetAddress();
- std::string p = addr ? ATSPI_PREFIX_PATH + addr.GetPath() : ATSPI_NULL_PATH;
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
- p,
- AtspiDbusInterfaceEventObject,
+ if(!IsUp() || obj->IsHidden())
+ {
+ return;
+ }
+
+ AddCoalescableMessage(CoalescableMessages::POST_RENDER, obj.get(), 0.5f, [=, weakObj = std::weak_ptr<Accessible>(obj)]() {
+ if(auto accessible = weakObj.lock())
+ {
+ Emit(accessible.get(), WindowEvent::POST_RENDER);
+ }
+ });
+}
+
+void BridgeObject::EmitCursorMoved(Accessible* obj, unsigned int cursorPosition)
+{
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CARET_MOVED])
+ {
+ return;
+ }
+
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
"TextCaretMoved",
"",
cursorPosition,
void BridgeObject::EmitTextChanged(Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string& content)
{
- const char* stateName = nullptr;
- switch(state)
+ static const std::unordered_map<TextChangedState, std::string_view> stateMap{
+ {TextChangedState::INSERTED, "insert"},
+ {TextChangedState::DELETED, "delete"},
+ };
+
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CHANGED])
{
- case TextChangedState::INSERTED:
- {
- stateName = "insert";
- break;
- }
- case TextChangedState::DELETED:
- {
- stateName = "delete";
- break;
- }
- case TextChangedState::MAX_COUNT:
- {
- break;
- }
+ return;
}
- if(stateName)
+
+ auto stateName = stateMap.find(state);
+
+ if(stateName != stateMap.end())
{
- auto addr = obj->GetAddress();
- std::string p = addr ? ATSPI_PREFIX_PATH + addr.GetPath() : ATSPI_NULL_PATH;
- dbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::string>, Address>(
- p,
- AtspiDbusInterfaceEventObject,
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::string>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
"TextChanged",
- stateName,
+ std::string{stateName->second},
position,
length,
{content},
{"", "root"});
}
}
+
+void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type)
+{
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::MOVED_OUT])
+ {
+ return;
+ }
+
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
+ "MoveOuted",
+ "",
+ static_cast<int>(type),
+ 0,
+ {0},
+ {"", "root"});
+}
+
+void BridgeObject::EmitSocketAvailable(Accessible* obj)
+{
+ if(!IsUp() || obj->IsHidden()) //TODO Suppress SocketAvailable event
+ {
+ return;
+ }
+
+ mDbusServer.emit2<Address, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::SOCKET),
+ "Available",
+ obj->GetAddress(),
+ {"", "root"});
+}
+
+void BridgeObject::EmitScrollStarted(Accessible* obj)
+{
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::SCROLL_STARTED])
+ {
+ return;
+ }
+
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
+ "ScrollStarted",
+ "",
+ 0,
+ 0,
+ {0},
+ {"", "root"});
+}
+
+void BridgeObject::EmitScrollFinished(Accessible* obj)
+{
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::SCROLL_FINISHED])
+ {
+ return;
+ }
+
+ mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
+ GetAccessiblePath(obj),
+ Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
+ "ScrollFinished",
+ "",
+ 0,
+ 0,
+ {0},
+ {"", "root"});
+}