#include "Atspi.hpp"
+#include "Singleton.hpp"
#include <memory>
#include <functional>
+#include <limits>
#define PRINT_ERROR_AND_FREE(error) \
do { \
} \
} while (0)
-#define GERROR_CHECK(error) \
- do { \
- PRINT_ERROR_AND_FREE(error); \
- error = nullptr; \
- } while (0)
-
#define EXIT_IF_NULLPTR(obj) \
do { \
if (!obj) { \
}
}
-static std::shared_ptr<AtspiAccessible> root_object;
+static AtspiAccessiblePtr root_object;
static std::vector<std::pair<std::string, std::string>> root_object_attributes;
-void hack_setRootObjectAttributes(std::shared_ptr<AtspiAccessible> obj, std::vector<std::pair<std::string, std::string>> attrs)
+template <typename T> static std::string getBusNameImpl(T *o)
+{
+ if (!o) return "";
+ auto z = atspi_accessible_get_bus_name(reinterpret_cast<AtspiAccessible *>(o), NULL);
+ std::string q = z;
+ g_free(z);
+ return std::move(q);
+}
+
+template <typename T> static std::string getPathImpl(T *o)
+{
+ if (!o) return "/org/a11y/atspi/null";
+ auto z = atspi_accessible_get_path(reinterpret_cast<AtspiAccessible *>(o), NULL);
+ std::string q = z;
+ g_free(z);
+ return "/org/a11y/atspi/accessible/" + q;
+}
+
+template <typename T> struct InterfaceNameFromType {
+ static const std::string interfaceName;
+};
+
+#define ADD_INTROSPECTION_FUNCTIONS(TYPE, NAME) \
+ template <> const std::string InterfaceNameFromType<Atspi ## TYPE>::interfaceName = \
+ ATSPI_DBUS_INTERFACE_ ## NAME; \
+ static std::string getBusName(const std::shared_ptr<Atspi ## TYPE> &o) \
+ { \
+ return getBusNameImpl(o.get()); \
+ } \
+ static std::string getPath(const std::shared_ptr<Atspi ## TYPE> &o) \
+ { \
+ return getPathImpl(o.get()); \
+ } \
+ static void convert(std::shared_ptr<Atspi ## TYPE> &r, \
+ const AtspiAccessiblePtr &obj) \
+ { \
+ r = { ATSPI_ ## NAME(obj.get()), g_object_unref }; \
+ } \
+ void Atspi::get ## TYPE ## Interface(const AtspiAccessiblePtr &obj, \
+ AsyncCallback<std::shared_ptr<Atspi ## TYPE>> callback) const \
+ { \
+ getInterface<Atspi ## TYPE>(obj, std::move(callback)); \
+ } \
+ std::string Atspi::getUniqueId(const std::shared_ptr<Atspi ## TYPE> &obj) const \
+ { \
+ if (!obj) \
+ return "(null)"; \
+ GError *error = nullptr; \
+ auto v = atspi_accessible_get_unique_id(ATSPI_ACCESSIBLE(obj.get()), &error); \
+ PRINT_ERROR_AND_FREE(error); \
+ if (!error) return "(failed)"; \
+ auto z = std::string { v }; \
+ g_free(v); \
+ return std::move(z); \
+ } \
+ AtspiAccessiblePtr Atspi::getBase( \
+ const std::shared_ptr<Atspi ## TYPE> &obj) const \
+ { \
+ if (!obj) return {}; \
+ return { ATSPI_ACCESSIBLE(obj.get()), g_object_unref }; \
+ }
+
+ADD_INTROSPECTION_FUNCTIONS(Accessible, ACCESSIBLE);
+ADD_INTROSPECTION_FUNCTIONS(Action, ACTION);
+ADD_INTROSPECTION_FUNCTIONS(Selection, SELECTION);
+ADD_INTROSPECTION_FUNCTIONS(Collection, COLLECTION);
+ADD_INTROSPECTION_FUNCTIONS(Value, VALUE);
+ADD_INTROSPECTION_FUNCTIONS(EditableText, EDITABLE_TEXT);
+
+#undef ADD_INTROSPECTION_FUNCTIONS
+
+void hack_setRootObjectAttributes(AtspiAccessiblePtr obj, std::vector<std::pair<std::string, std::string>> attrs)
{
root_object = std::move(obj);
root_object_attributes = std::move(attrs);
: eldbus(), connection(efl::eldbus::session)
{
ConnectAtClient();
+
+ DBus proxy{"org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus"};
+ auto addr = proxy.method<std::string()>("GetAddress").call();
+
+ if (!addr) {
+ ERROR("failed");
+ } else {
+ eldbusConnection = { eldbus_address_connection_get((*addr).c_str()), eldbus_connection_unref };
+ }
}
Atspi::~Atspi()
if (error != 0 && error != 1) {
ERROR("Error code %d", error);
return false;
- } else if (error == 1)
+ } else if (error == 1) {
INFO("Atspi has been already initialized");
+ }
auto dbusStatus = setPropertyBool("org.a11y.Bus", "/org/a11y/bus", "org.a11y.Status", "IsEnabled", true);
if (!dbusStatus) {
return true;
}
-std::shared_ptr<AtspiAccessible> Atspi::getObjectInRelation(const std::shared_ptr<AtspiAccessible> &accessibleObj, AtspiRelationType searchType) const
+Optional<std::string> Atspi::getName(const AtspiAccessiblePtr &accessibleObj) const
+{
+ GError *error = nullptr;
+ auto name = atspi_accessible_get_name(accessibleObj.get(), &error);
+ if (error) {
+ PRINT_ERROR_AND_FREE(error);
+ if (name) g_free(name);
+ return {};
+ }
+ std::string z = name;
+ g_free(name);
+ return std::move(z);
+}
+
+Optional<AtspiRole> Atspi::getRole(const AtspiAccessiblePtr &accessibleObj) const
+{
+ GError *error = nullptr;
+ auto role = atspi_accessible_get_role(accessibleObj.get(), &error);
+ if (error) {
+ PRINT_ERROR_AND_FREE(error);
+ return {};
+ }
+ return role;
+}
+
+Atspi::StateSet Atspi::getStateSet(const AtspiAccessiblePtr &accessibleObj) const
+{
+ auto states = atspi_accessible_get_state_set(accessibleObj.get());
+ StateSet result;
+ auto v = states->states;
+ g_object_unref(states);
+ for (unsigned int i = 0; i < result.size(); ++i) {
+ if (v & 1) result.set(i);
+ v >>= 1;
+ }
+ return result;
+}
+
+Optional<unsigned int> Atspi::getProcessId(const AtspiAccessiblePtr &accessibleObj) const
+{
+ GError *error = nullptr;
+ auto pid = atspi_accessible_get_process_id(accessibleObj.get(), &error);
+ if (error) {
+ PRINT_ERROR_AND_FREE(error);
+ return {};
+ }
+ return (unsigned int)pid;
+}
+
+AtspiAccessiblePtr Atspi::getObjectInRelation(const AtspiAccessiblePtr &accessibleObj, AtspiRelationType searchType) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
auto relations = atspi_accessible_get_relation_set(accessibleObj.get(), &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
if (!relations) {
DEBUG("Relation set do not exist");
return {};
}
- DEBUG("Relations found: %d", relations->len);
AtspiAccessible *relationObj = nullptr;
for (unsigned i = 0; i < relations->len; ++i) {
AtspiRelation *relation = g_array_index(relations, AtspiRelation *, i);
auto type = atspi_relation_get_relation_type(relation);
- DEBUG("Relation type: %d", type);
if (type == searchType) {
- DEBUG("Searched relation found");
relationObj = atspi_relation_get_target(relation, 0);
break;
}
return {relationObj, g_object_unref};
}
-std::vector<std::pair<std::string, std::string>> Atspi::getAttributes(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+template <typename T> DBus Atspi::getProxy(const std::shared_ptr<T> &obj, const std::string &interface) const
+{
+ auto bus = getBusName(obj);
+ auto path = getPath(obj);
+
+ return DBus { bus, path, interface, eldbusConnection };
+}
+
+template <typename> struct PropertyCallback;
+template <typename RetType, typename ... ARGS> struct PropertyCallback<RetType(ARGS...)> {
+ using VariantReturnType = EldbusVariant<RetType>;
+ using RealReturnType = RetType;
+ using CallType = VariantReturnType(std::string, std::string, ARGS...);
+};
+template <typename> struct returnType;
+template <typename RetType, typename ... ARGS> struct returnType<RetType(ARGS...)> {
+ using type = RetType;
+};
+template <typename CallType, typename InterfaceType, typename ... ARGS> void callFunction(
+ const EldbusConnectionCallbackHandle &eldbusConnection,
+ const std::string &interface,
+ const std::shared_ptr<InterfaceType> &obj,
+ const std::string &func_name,
+ typename detail::AsyncCallbackHelper<typename returnType<CallType>::type>::type callback,
+ ARGS &&... args
+)
+{
+ auto bus = getBusName(obj);
+ auto path = getPath(obj);
+
+ auto dbus = DBus { bus, path, interface, eldbusConnection };
+ dbus.method<CallType>(func_name).asyncCall(std::forward<ARGS>(args)..., std::move(callback));
+}
+
+template <typename CallType, typename InterfaceType, typename ... ARGS> void callFunction(
+ const EldbusConnectionCallbackHandle &eldbusConnection,
+ const std::shared_ptr<InterfaceType> &obj,
+ const std::string &func_name,
+ typename detail::AsyncCallbackHelper<typename returnType<CallType>::type>::type callback,
+ ARGS &&... args
+)
+{
+ callFunction<CallType>(eldbusConnection, InterfaceNameFromType<InterfaceType>::interfaceName,
+ obj, func_name, std::move(callback), std::forward<ARGS>(args)...);
+}
+
+template <typename CallType, typename InterfaceType, typename ... ARGS> void getProperty(
+ const EldbusConnectionCallbackHandle &eldbusConnection,
+ const std::string &interface,
+ const std::shared_ptr<InterfaceType> &obj,
+ const std::string &func_name,
+ typename detail::AsyncCallbackHelper<typename returnType<CallType>::type>::type callback,
+ ARGS &&... args
+)
+{
+ callFunction<typename PropertyCallback<CallType>::CallType>(
+ eldbusConnection, DBUS_INTERFACE_PROPERTIES, obj, "Get",
+ [callback](Optional<typename PropertyCallback<CallType>::VariantReturnType> val) {
+ if (!val) callback({});
+ else callback(std::move((*val).value));
+ },
+ interface, func_name);
+}
+
+template <typename CallType, typename InterfaceType, typename ... ARGS> void getProperty(
+ const EldbusConnectionCallbackHandle &eldbusConnection,
+ const std::shared_ptr<InterfaceType> &obj,
+ const std::string &func_name,
+ typename detail::AsyncCallbackHelper<typename returnType<CallType>::type>::type callback,
+ ARGS &&... args
+)
+{
+ getProperty<CallType>(eldbusConnection, InterfaceNameFromType<InterfaceType>::interfaceName,
+ obj, func_name, std::move(callback), std::forward<ARGS>(args)...);
+}
+
+void Atspi::getAttributes(const AtspiAccessiblePtr &accessibleObj,
+ AsyncCallback<std::unordered_map<std::string, std::string>> callback) const
+{
+ callFunction<std::unordered_map<std::string, std::string>()>(
+ eldbusConnection,
+ accessibleObj,
+ "GetAttributes",
+ std::move(callback)
+ );
+}
+
+void Atspi::doActionName(const AtspiActionPtr &accessibleObj, const std::string &action, AsyncCallback<bool> callback) const
+{
+ callFunction<bool(std::string)>(
+ eldbusConnection,
+ accessibleObj,
+ "DoActionName",
+ std::move(callback),
+ action
+ );
+}
+
+void Atspi::getParent(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<AtspiAccessiblePtr> callback) const
+{
+ getProperty<AtspiAccessiblePtr()>(
+ eldbusConnection,
+ accessibleObj,
+ "Parent",
+ std::move(callback)
+ );
+}
+
+void Atspi::getIndexInParent(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<int> callback) const
+{
+ callFunction<int()>(
+ eldbusConnection,
+ accessibleObj,
+ "GetIndexInParent",
+ std::move(callback)
+ );
+}
+
+void Atspi::selectChild(const AtspiSelectionPtr &accessibleObj, int index, AsyncCallback<void> callback) const
+{
+ callFunction<void(int)>(
+ eldbusConnection,
+ accessibleObj,
+ "SelectChild",
+ std::move(callback),
+ index
+ );
+}
+
+void Atspi::getName(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::string> callback) const
+{
+ getProperty<std::string()>(
+ eldbusConnection,
+ accessibleObj,
+ "Name",
+ std::move(callback)
+ );
+}
+
+void Atspi::getRole(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<AtspiRole> callback) const
+{
+ callFunction<uint32_t()>(
+ eldbusConnection,
+ accessibleObj,
+ "GetRole",
+ [callback](Optional<uint32_t> val) {
+ if (!val) callback({});
+ else callback((AtspiRole)*val);
+ }
+ );
+}
+
+void Atspi::getChildrenCount(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<size_t> callback) const
+{
+ getProperty<int()>(
+ eldbusConnection,
+ accessibleObj,
+ "ChildCount",
+ [callback](Optional<int> val) {
+ if (!val || *val < 0)
+ callback({});
+ else
+ callback((size_t)*val);
+ }
+ );
+}
+
+void Atspi::getChildAtIndex(const AtspiAccessiblePtr &accessibleObj, size_t index, AsyncCallback<AtspiAccessiblePtr> callback) const
+{
+ callFunction<AtspiAccessiblePtr(int)>(
+ eldbusConnection,
+ accessibleObj,
+ "GetChildAtIndex",
+ std::move(callback),
+ (int)index
+ );
+}
+
+void Atspi::getStateSet(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<StateSet> callback) const
+{
+ callFunction<std::array<uint32_t, 2>()>(
+ eldbusConnection,
+ accessibleObj,
+ "GetState",
+ [callback](Optional<std::array<uint32_t, 2>> data) {
+ if (data) {
+ StateSet s;
+ for (size_t i = 0; i < (size_t)ATSPI_STATE_LAST_DEFINED; ++i) {
+ if ((*data)[i >> 5] & (1 << (i & 31))) {
+ s[i] = true;
+ assert(s[i]);
+ }
+ }
+ callback(s);
+ } else {
+ callback({});
+ }
+ }
+ );
+}
+
+void Atspi::getChildren(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::vector<AtspiAccessiblePtr>> callback) const
+{
+ getChildrenCount(accessibleObj,
+ [accessibleObj, callback](Optional<size_t> childrenCount) {
+ if (!childrenCount) {
+ callback({});
+ } else {
+ struct State {
+ AsyncCallback<std::vector<AtspiAccessiblePtr>> callback;
+ size_t todoCount;
+ std::vector<AtspiAccessiblePtr> children;
+ bool failed = false;
+ };
+ auto state = std::make_shared<State>();
+ state->callback = std::move(callback);
+ state->children.resize(*childrenCount);
+ state->todoCount = *childrenCount;
+ for (size_t index = 0; index < *childrenCount; ++index) {
+ auto cback = [state, index](Optional<AtspiAccessiblePtr> child) {
+ if (state->failed)
+ return;
+ if (!child) {
+ state->failed = true;
+ state->callback({});
+ return;
+ }
+ state->children[index] = std::move(*child);
+ assert(state->todoCount > 0);
+ --state->todoCount;
+ if (state->todoCount == 0)
+ state->callback(std::move(state->children));
+ };
+ Singleton<Atspi>::instance().getChildAtIndex(accessibleObj, index, std::move(cback));
+ }
+ }
+ });
+}
+
+template <typename T> void Atspi::getInterface(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::shared_ptr<T>> callback) const
+{
+ callFunction<std::vector<std::string>()>(
+ eldbusConnection,
+ accessibleObj,
+ "GetInterfaces",
+ [this, callback, accessibleObj](Optional<std::vector<std::string>> val) {
+ const auto interfaceName = InterfaceNameFromType<T>::interfaceName;
+ if (val) {
+ for (auto &z : *val) {
+ if (z == interfaceName) {
+ std::shared_ptr<T> r;
+ convert(r, accessibleObj);
+ callback(std::move(r));
+ return;
+ }
+ }
+ }
+ std::string interfaces;
+ for (auto &z : *val) {
+ if (!interfaces.empty()) interfaces += " ";
+ interfaces += z;
+ }
+ callback({});
+ }
+ );
+}
+
+void Atspi::getMatchedElements(const AtspiCollectionPtr &rootObj, AtspiCollectionSortOrder sortOrder,
+ size_t maximumFoundElements, Matcher m, bool reverse,
+ AsyncCallback<std::vector<AtspiAccessiblePtr>> callback)
+{
+ assert(maximumFoundElements <= (size_t)std::numeric_limits<int32_t>::max());
+
+ auto bus = getBusName(rootObj);
+ auto path = getPath(rootObj);
+
+ auto pr = DBus { bus, path, ATSPI_DBUS_INTERFACE_COLLECTION, eldbusConnection };
+ std::get<8>(m.value) = reverse;
+ auto mm = pr.method<std::vector<AtspiAccessiblePtr>(decltype(Matcher::value), uint32_t, int32_t, bool)>("GetMatches");
+ auto v = mm.call(
+ std::move(m.value),
+ (uint32_t)sortOrder,
+ (int32_t)maximumFoundElements,
+ true);
+ callback(v);
+}
+
+void Atspi::getAtPoint(Point pt, CoordType type, const AtspiAccessiblePtr &root, AsyncCallback<AtspiAccessiblePtr> callback) const
+{
+ AtspiCoordType ctype = ATSPI_COORD_TYPE_SCREEN;
+ switch (type) {
+ case CoordType::Screen:
+ ctype = ATSPI_COORD_TYPE_SCREEN;
+ break;
+ case CoordType::Window:
+ ctype = ATSPI_COORD_TYPE_WINDOW;
+ break;
+ }
+ using returnType = std::tuple<AtspiAccessiblePtr, uint8_t, AtspiAccessiblePtr>;
+ struct handler {
+ const Atspi *atspi;
+ Point pt;
+ uint32_t ctype;
+ AsyncCallback<AtspiAccessiblePtr> callback;
+
+ static void process(std::shared_ptr<handler> self, Optional<returnType> value)
+ {
+ if (!value) {
+ self->callback({});
+ } else {
+ auto &ptr = std::get<0>(*value);
+ auto recurse = std::get<1>(*value);
+ auto &deputy = std::get<2>(*value);
+ if (!ptr && deputy)
+ ptr = std::move(deputy);
+ if (!recurse) {
+ if (!ptr) {
+ self->callback({});
+ } else {
+ self->callback(std::move(ptr));
+ }
+ return;
+ }
+ callFunction<returnType(int32_t, int32_t, uint32_t)>(
+ self->atspi->eldbusConnection,
+ ptr,
+ "GetNavigableAtPoint",
+ [self](Optional<returnType> value) {
+ process(std::move(self), std::move(value));
+ },
+ self->pt.x, self->pt.y, self->ctype);
+ }
+ }
+ };
+ auto h = std::make_shared<handler>(handler{this, pt, (uint32_t)ctype, std::move(callback)});
+ callFunction<std::tuple<AtspiAccessiblePtr, uint8_t, AtspiAccessiblePtr>(int32_t, int32_t, uint32_t)>(
+ eldbusConnection,
+ root,
+ "GetNavigableAtPoint",
+ [h](Optional<returnType> value) {
+ handler::process(std::move(h), std::move(value));
+ },
+ pt.x, pt.y, (uint32_t)ctype);
+}
+
+void Atspi::getAllAcceptedObjects(const AtspiAccessiblePtr &root, AsyncCallback<std::tuple<std::vector<AcceptedObjectInfo>, Rectangle>> callback) const
+{
+ using returnType = std::tuple<int32_t, int32_t, int32_t, int32_t,
+ std::vector<std::tuple<AtspiAccessiblePtr, int32_t, int32_t, int32_t, int32_t>>>;
+
+ callFunction<returnType()>(
+ eldbusConnection,
+ root,
+ "GetAllAcceptedObjects",
+ [ = ](Optional<returnType> value) {
+ if (!value) {
+ callback({});
+ } else {
+ std::tuple<std::vector<AcceptedObjectInfo>, Rectangle> res;
+ auto &ois = std::get<0>(res);
+ std::get<1>(res) = { { std::get<0>(*value), std::get<1>(*value) }, { std::get<2>(*value), std::get<3>(*value) }};
+ auto &v = std::get<4>(*value);
+ ois.reserve(v.size());
+ for (auto &a : v) {
+ ois.push_back({});
+ auto &o = ois.back();
+ o.object = std::move(std::get<0>(a));
+ o.pos = { { std::get<1>(a), std::get<2>(a)}, { std::get<3>(a), std::get<4>(a) } };
+ }
+ callback(std::move(res));
+ }
+ }
+ );
+}
+
+std::vector<std::pair<std::string, std::string>> Atspi::getAttributes(const AtspiAccessiblePtr &accessibleObj) const
{
assert(accessibleObj == root_object);
return root_object_attributes;
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
GHashTable *attr = atspi_accessible_get_attributes(accessibleObj.get(), nullptr);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
if (!attr) {
DEBUG("object do not has attributes");
return {};
std::vector<std::pair<std::string, std::string>> attributes;
while (g_hash_table_iter_next(&attr_iter, &attr_key, &attr_value)) {
attributes.emplace_back((char *) attr_key, (char *) attr_value);
- DEBUG("atribute: %s = %s", std::get<0>(attributes.back()).c_str(), std::get<1>(attributes.back()).c_str());
}
g_hash_table_unref(attr);
#endif
}
-std::shared_ptr<AtspiAction> Atspi::getActionInterface(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+AtspiActionPtr Atspi::getActionInterface(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
auto action = atspi_accessible_get_action_iface(accessibleObj.get());
return {action, g_object_unref};
}
-bool Atspi::doAction(const std::shared_ptr<AtspiAction> &accessibleObj, int action) const
+bool Atspi::doAction(const AtspiActionPtr &accessibleObj, int action) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
auto status = atspi_action_do_action(accessibleObj.get(), action, &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
if (!status) {
DEBUG("Action (%d) execution failure", action);
return false;
return true;
}
-bool Atspi::doActionName(const std::shared_ptr<AtspiAction> &accessibleObj, const std::string &action) const
+bool Atspi::doActionName(const AtspiActionPtr &accessibleObj, const std::string &action) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
auto status = atspi_action_do_action_name(accessibleObj.get(), action.c_str(), &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
if (!status) {
DEBUG("Action (%s) execution failure", action.c_str());
return false;
return true;
}
-std::shared_ptr<AtspiValue> Atspi::getValueInterface(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+AtspiCollectionPtr Atspi::getCollectionInterface(const AtspiAccessiblePtr &accessibleObj) const
+{
+ EXIT_IF_NULLPTR(accessibleObj);
+ auto collectionInterface = atspi_accessible_get_collection_iface(accessibleObj.get());
+ if (!collectionInterface)
+ DEBUG("Object %p do not has collection interface", accessibleObj.get());
+ return {collectionInterface, g_object_unref};
+}
+
+AtspiValuePtr Atspi::getValueInterface(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
auto valueInterface = atspi_accessible_get_value_iface(accessibleObj.get());
return {valueInterface, g_object_unref};
}
-Optional<double> Atspi::getCurrentValue(const std::shared_ptr<AtspiValue> &valueInterface) const
+Optional<double> Atspi::getCurrentValue(const AtspiValuePtr &valueInterface) const
{
return getValueTemplateFunction<double>(atspi_value_get_current_value, valueInterface.get());
}
-bool Atspi::setCurrentValue(const std::shared_ptr<AtspiValue> &valueInterface, double newValue) const
+bool Atspi::setCurrentValue(const AtspiValuePtr &valueInterface, double newValue) const
{
EXIT_IF_NULLPTR(valueInterface);
GError *error = nullptr;
auto isSuccessful = atspi_value_set_current_value(valueInterface.get(), newValue, &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
return isSuccessful;
}
-Optional<double> Atspi::getMinimumIncrement(const std::shared_ptr<AtspiValue> &valueInterface) const
+Optional<double> Atspi::getMinimumIncrement(const AtspiValuePtr &valueInterface) const
{
return getValueTemplateFunction<double>(atspi_value_get_minimum_increment, valueInterface.get());
}
-Optional<double> Atspi::getMaximumValue(const std::shared_ptr<AtspiValue> &valueInterface) const
+Optional<double> Atspi::getMaximumValue(const AtspiValuePtr &valueInterface) const
{
return getValueTemplateFunction<double>(atspi_value_get_maximum_value, valueInterface.get());
}
-Optional<double> Atspi::getMinimumValue(const std::shared_ptr<AtspiValue> &valueInterface) const
+Optional<double> Atspi::getMinimumValue(const AtspiValuePtr &valueInterface) const
{
return getValueTemplateFunction<double>(atspi_value_get_minimum_value, valueInterface.get());
}
-std::shared_ptr<AtspiAccessible> Atspi::getDesktop() const
+AtspiAccessiblePtr Atspi::getDesktop() const
{
auto res = atspi_get_desktop(0);
ASSERT(res);
- DEBUG("root is %s", atspi_accessible_get_unique_id(res, NULL));
return {res, g_object_unref};
}
-std::shared_ptr<AtspiAccessible> Atspi::getAtPoint(int x, int y, CoordType type, std::shared_ptr<AtspiAccessible> root) const
+AtspiAccessiblePtr Atspi::getAtPoint(Point pt, CoordType type, AtspiAccessiblePtr root) const
{
AtspiCoordType ctype = ATSPI_COORD_TYPE_SCREEN;
switch (type) {
}
if (!root) {
- auto is_visible = [](const std::shared_ptr<AtspiAccessible> &ptr) -> bool {
+ auto is_visible = [](const AtspiAccessiblePtr & ptr) -> bool {
AtspiStateSet *state_set = atspi_accessible_get_state_set(ptr.get());
auto visible = bool(atspi_state_set_contains(state_set, ATSPI_STATE_SHOWING));
g_object_unref(state_set);
return visible;
};
- auto get_at_point = [ = ](const std::shared_ptr<AtspiAccessible> &ptr) -> std::shared_ptr<AtspiAccessible> {
+ auto get_at_point = [ = ](const AtspiAccessiblePtr & ptr) -> AtspiAccessiblePtr {
if (!ATSPI_IS_COMPONENT(ptr.get()))
{
DEBUG("%s is not a component", atspi_accessible_get_unique_id(ptr.get(), NULL));
}
auto compo = ATSPI_COMPONENT(ptr.get());
GError *error = nullptr;
- auto res = atspi_component_get_accessible_at_point(compo, x, y, ctype, &error);
- GERROR_CHECK(error);
- if (res)
- DEBUG("result is %s", atspi_accessible_get_unique_id(res, NULL));
- return std::shared_ptr<AtspiAccessible>{res, g_object_unref};
+ auto res = atspi_component_get_accessible_at_point(compo, pt.x, pt.y, ctype, &error);
+ PRINT_ERROR_AND_FREE(error);
+ return AtspiAccessiblePtr{res, g_object_unref};
};
auto desktop = getDesktop();
auto chs = getChildren(desktop);
- for (auto c : chs) {
- while (true) {
- auto n = get_at_point(c);
- if (!n) break;
- c = std::move(n);
- }
- if (is_visible(c)) {
- root = c;
- break;
+ if (chs) {
+ for (auto c : *chs) {
+ while (true) {
+ auto n = get_at_point(c);
+ if (!n) break;
+ c = std::move(n);
+ }
+ if (is_visible(c)) {
+ root = c;
+ break;
+ }
}
}
if (!root) {
return {};
}
}
- DEBUG("root is %s", atspi_accessible_get_unique_id(root.get(), NULL));
GError *error = nullptr;
- auto res = atspi_accessible_get_navigable_at_point(root.get(), x, y, ctype, &error);
- GERROR_CHECK(error);
- if (res)
- DEBUG("result is %s", atspi_accessible_get_unique_id(res, NULL));
+ auto res = atspi_accessible_get_navigable_at_point(root.get(), pt.x, pt.y, ctype, &error);
+ PRINT_ERROR_AND_FREE(error);
return {res, g_object_unref};
}
-Optional<size_t> Atspi::getChildrenCount(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+Optional<size_t> Atspi::getChildrenCount(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
return (size_t)count;
}
-std::shared_ptr<AtspiAccessible> Atspi::getChildAtIndex(const std::shared_ptr<AtspiAccessible> &accessibleObj, size_t index) const
+AtspiAccessiblePtr Atspi::getChildAtIndex(const AtspiAccessiblePtr &accessibleObj, size_t index) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
auto res = atspi_accessible_get_child_at_index(accessibleObj.get(), (gint)index, &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
return {res, g_object_unref};
}
-std::vector<std::shared_ptr<AtspiAccessible>> Atspi::getChildren(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+Optional<std::vector<AtspiAccessiblePtr>> Atspi::getChildren(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
auto count = getChildrenCount(accessibleObj);
if (!count) return {};
- std::vector<std::shared_ptr<AtspiAccessible>> tmp(*count);
+ std::vector<AtspiAccessiblePtr> tmp(*count);
for (size_t i = 0; i < *count; ++i) {
auto c = getChildAtIndex(accessibleObj, i);
if (!c) return {};
tmp.push_back(std::move(c));
}
- return tmp;
+ return std::move(tmp);
}
-std::string Atspi::getUniqueId(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+AtspiAccessiblePtr Atspi::make(AtspiAccessible *obj, bool increase_reference) const
{
- EXIT_IF_NULLPTR(accessibleObj);
- GError *error = nullptr;
- auto v = atspi_accessible_get_unique_id(accessibleObj.get(), &error);
- GERROR_CHECK(error);
- if (!v) return {};
+ if (!obj) return {};
+ if (increase_reference)
+ g_object_ref(obj);
+ return { obj, g_object_unref };
+}
- std::string z = v;
- g_free(v);
- return std::move(z);
+AtspiAccessiblePtr Atspi::make(const std::string &bus, const std::string &path) const
+{
+ return { ref_accessible(bus.c_str(), path.c_str()), g_object_unref };
}
-std::shared_ptr<AtspiAccessible> Atspi::getParent(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+AtspiAccessiblePtr Atspi::getParent(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
auto v = atspi_accessible_get_parent(accessibleObj.get(), &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
if (!v) return {};
return {v, g_object_unref};
}
-Optional<size_t> Atspi::getIndexInParent(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+Optional<size_t> Atspi::getIndexInParent(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
auto v = atspi_accessible_get_index_in_parent(accessibleObj.get(), &error);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
if (v < 0) return {};
return (size_t)v;
}
-std::shared_ptr<AtspiSelection> Atspi::getSelectionInterface(const std::shared_ptr<AtspiAccessible> &accessibleObj) const
+AtspiSelectionPtr Atspi::getSelectionInterface(const AtspiAccessiblePtr &accessibleObj) const
{
EXIT_IF_NULLPTR(accessibleObj);
auto res = atspi_accessible_get_selection_iface(accessibleObj.get());
return {res, g_object_unref};
}
-bool Atspi::selectChild(const std::shared_ptr<AtspiSelection> &accessibleObj, size_t index) const
+bool Atspi::selectChild(const AtspiSelectionPtr &accessibleObj, size_t index) const
{
EXIT_IF_NULLPTR(accessibleObj);
GError *error = nullptr;
atspi_selection_select_child(accessibleObj.get(), (int)index, &error);
bool isSuccessful = (error == nullptr);
- GERROR_CHECK(error);
+ PRINT_ERROR_AND_FREE(error);
return isSuccessful;
}
-#ifndef ATSPI_ADAPTER_HPP
-#define ATSPI_ADAPTER_HPP
+#ifndef ATSPI_HPP
+#define ATSPI_HPP
#include "Optional.hpp"
#include "eldbus.hpp"
+#include "DBus.hpp"
+#include "Geometry.hpp"
#include <atspi/atspi.h>
#include <memory>
#include <vector>
+#include <bitset>
+#include <array>
+
+namespace detail
+{
+ template <typename T> struct AsyncCallbackHelper {
+ using type = std::function<void(Optional<T>)>;
+ };
+ template <> struct AsyncCallbackHelper<void> {
+ using type = std::function<void(bool)>;
+ };
+}
+
+using AtspiAccessiblePtr = std::shared_ptr<AtspiAccessible>;
+using AtspiActionPtr = std::shared_ptr<AtspiAction>;
+using AtspiSelectionPtr = std::shared_ptr<AtspiSelection>;
+using AtspiCollectionPtr = std::shared_ptr<AtspiCollection>;
+using AtspiValuePtr = std::shared_ptr<AtspiValue>;
+using AtspiEditableTextPtr = std::shared_ptr<AtspiEditableText>;
+template <typename T> using AsyncCallback = typename detail::AsyncCallbackHelper<T>::type;
class Atspi
{
public:
+ using StateSet = std::bitset<ATSPI_STATE_LAST_DEFINED>;
+
enum class CoordType {
Screen,
Window
Atspi();
~Atspi();
- std::shared_ptr<AtspiAccessible> getObjectInRelation(const std::shared_ptr<AtspiAccessible> &accessibleObj, AtspiRelationType searchType) const;
- std::vector<std::pair<std::string, std::string>> getAttributes(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
+ AtspiAccessiblePtr make(const std::string &bus, const std::string &path) const;
+ AtspiAccessiblePtr make(AtspiAccessible *obj, bool increase_reference) const;
+ AtspiAccessiblePtr getObjectInRelation(const AtspiAccessiblePtr &accessibleObj, AtspiRelationType searchType) const;
+ std::vector<std::pair<std::string, std::string>> getAttributes(const AtspiAccessiblePtr &accessibleObj) const;
- std::shared_ptr<AtspiAction> getActionInterface(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- bool doAction(const std::shared_ptr<AtspiAction> &accessibleObj, int action) const;
- bool doActionName(const std::shared_ptr<AtspiAction> &accessibleObj, const std::string &action) const;
+ AtspiActionPtr getActionInterface(const AtspiAccessiblePtr &accessibleObj) const;
+ bool doAction(const AtspiActionPtr &accessibleObj, int action) const;
+ bool doActionName(const AtspiActionPtr &accessibleObj, const std::string &action) const;
- std::shared_ptr<AtspiValue> getValueInterface(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- Optional<double> getCurrentValue(const std::shared_ptr<AtspiValue> &valueInterface) const;
- bool setCurrentValue(const std::shared_ptr<AtspiValue> &valueInterface, double newValue) const;
- Optional<double> getMinimumIncrement(const std::shared_ptr<AtspiValue> &valueInterface) const;
- Optional<double> getMaximumValue(const std::shared_ptr<AtspiValue> &valueInterface) const;
- Optional<double> getMinimumValue(const std::shared_ptr<AtspiValue> &valueInterface) const;
+ AtspiCollectionPtr getCollectionInterface(const AtspiAccessiblePtr &accessibleObj) const;
+ AtspiValuePtr getValueInterface(const AtspiAccessiblePtr &accessibleObj) const;
+ Optional<double> getCurrentValue(const AtspiValuePtr &valueInterface) const;
+ bool setCurrentValue(const AtspiValuePtr &valueInterface, double newValue) const;
+ Optional<double> getMinimumIncrement(const AtspiValuePtr &valueInterface) const;
+ Optional<double> getMaximumValue(const AtspiValuePtr &valueInterface) const;
+ Optional<double> getMinimumValue(const AtspiValuePtr &valueInterface) const;
+
+ AtspiAccessiblePtr getDesktop() const;
+ AtspiAccessiblePtr getAtPoint(Point pt, CoordType type, AtspiAccessiblePtr root) const;
+ Optional<size_t> getChildrenCount(const AtspiAccessiblePtr &accessibleObj) const;
+ Optional<unsigned int> getProcessId(const AtspiAccessiblePtr &accessibleObj) const;
+ AtspiAccessiblePtr getChildAtIndex(const AtspiAccessiblePtr &accessibleObj, size_t index) const;
+ Optional<std::vector<AtspiAccessiblePtr>> getChildren(const AtspiAccessiblePtr &accessibleObj) const;
+ Optional<AtspiRole> getRole(const AtspiAccessiblePtr &accessibleObj) const;
+ Optional<std::string> getName(const AtspiAccessiblePtr &accessibleObj) const;
+ StateSet getStateSet(const AtspiAccessiblePtr &accessibleObj) const;
+
+ AtspiAccessiblePtr getParent(const AtspiAccessiblePtr &accessibleObj) const;
+ Optional<size_t> getIndexInParent(const AtspiAccessiblePtr &accessibleObj) const;
+ AtspiSelectionPtr getSelectionInterface(const AtspiAccessiblePtr &accessibleObj) const;
+ bool selectChild(const AtspiSelectionPtr &accessibleObj, size_t index) const;
+
+ struct Matcher {
+ std::tuple <
+ std::array<int32_t, 2>, int32_t,// states & match type
+ std::unordered_map<std::string, std::string>, int32_t, // attributes & match type
+ std::array<int32_t, 4>, int32_t, // roles & match type
+ std::vector<std::string>, int32_t, // interfaces & match type
+ bool // invert
+ > value = {
+ { 0, 0 }, ATSPI_Collection_MATCH_INVALID,
+ {}, ATSPI_Collection_MATCH_INVALID,
+ { 0, 0, 0, 0}, ATSPI_Collection_MATCH_INVALID,
+ {}, ATSPI_Collection_MATCH_INVALID,
+ false
+ };
+ struct Index {
+ enum {
+ States, StatesMatchType,
+ Attributes, AttributesMatchType,
+ Roles, RolesMatchType,
+ Interfaces, InterfacesMatchType,
+ };
+ };
+ Matcher &states(std::initializer_list<AtspiStateType> st, AtspiCollectionMatchType type)
+ {
+ for (auto a : st)
+ std::get<Index::States>(value)[a >> 5] |= 1 << (a & 31);
+ std::get<Index::StatesMatchType>(value) = (int32_t)type;
+ return *this;
+ }
+ Matcher &attributes(std::unordered_map<std::string, std::string> st, AtspiCollectionMatchType type)
+ {
+ std::get<Index::Attributes>(value) = std::move(st);
+ std::get<Index::AttributesMatchType>(value) = (int32_t)type;
+ return *this;
+ }
+ template <typename A> Matcher &attributes(A begin, A end, AtspiCollectionMatchType type)
+ {
+ while (begin != end)
+ std::get<Index::Attributes>(value).insert(*begin++);
+ std::get<Index::AttributesMatchType>(value) = (int32_t)type;
+ return *this;
+ }
+ Matcher &roles(std::initializer_list<AtspiRole> st, AtspiCollectionMatchType type)
+ {
+ for (auto a : st)
+ std::get<Index::Roles>(value)[a >> 5] |= 1 << (a & 31);
+ std::get<Index::RolesMatchType>(value) = (int32_t)type;
+ return *this;
+ }
+ Matcher &interfaces(std::vector<std::string> st, AtspiCollectionMatchType type)
+ {
+ std::get<Index::Interfaces>(value) = std::move(st);
+ std::get<Index::InterfacesMatchType>(value) = (int32_t)type;
+ return *this;
+ }
+ template <typename A> Matcher &interfaces(A begin, A end, AtspiCollectionMatchType type)
+ {
+ while (begin != end)
+ std::get<Index::Interfaces>(value).push_back(*begin++);
+ std::get<Index::InterfacesMatchType>(value) = (int32_t)type;
+ return *this;
+ }
+ };
+ void getMatchedElements(const AtspiCollectionPtr &root, AtspiCollectionSortOrder sortOrder,
+ size_t maximumFoundElements, Matcher m, bool reverse, AsyncCallback<std::vector<AtspiAccessiblePtr>> callback);
+ void getChildrenCount(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<size_t> callback) const;
+ void getChildAtIndex(const AtspiAccessiblePtr &accessibleObj, size_t index, AsyncCallback<AtspiAccessiblePtr> callback) const;
+ void getChildren(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::vector<AtspiAccessiblePtr>> callback) const;
+ void getName(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::string> callback) const;
+ void getRole(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<AtspiRole> callback) const;
+ void getAttributes(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::unordered_map<std::string, std::string>> callback) const;
+ void doActionName(const AtspiActionPtr &accessibleObj, const std::string &action, AsyncCallback<bool> callback) const;
+ void getParent(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<AtspiAccessiblePtr> callback) const;
+ void getIndexInParent(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<int> callback) const;
+ void selectChild(const AtspiSelectionPtr &accessibleObj, int index, AsyncCallback<void> callback) const;
+ void getStateSet(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<StateSet> callback) const;
+ struct AcceptedObjectInfo {
+ AtspiAccessiblePtr object;
+ Rectangle pos;
+ };
+ void getAllAcceptedObjects(const AtspiAccessiblePtr &root, AsyncCallback<std::tuple<std::vector<AcceptedObjectInfo>, Rectangle>> callback) const;
+ void getAtPoint(Point pt, CoordType type, const AtspiAccessiblePtr &root, AsyncCallback<AtspiAccessiblePtr> callback) const;
- std::shared_ptr<AtspiAccessible> getDesktop() const;
- std::shared_ptr<AtspiAccessible> getAtPoint(int x, int y, CoordType type, std::shared_ptr<AtspiAccessible> root = {}) const;
- Optional<size_t> getChildrenCount(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- std::shared_ptr<AtspiAccessible> getChildAtIndex(const std::shared_ptr<AtspiAccessible> &accessibleObj, size_t index) const;
- std::vector<std::shared_ptr<AtspiAccessible>> getChildren(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- std::string getUniqueId(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
+#define ADD_INTROSPECTION_FUNCTIONS(TYPE, NAME) \
+ void get ## TYPE ## Interface(const AtspiAccessiblePtr &obj, \
+ AsyncCallback<std::shared_ptr<Atspi ## TYPE>> callback) const; \
+ std::string getUniqueId(const std::shared_ptr<Atspi ## TYPE> &obj) const; \
+ AtspiAccessiblePtr getBase(const std::shared_ptr<Atspi ## TYPE> &) const;
- std::shared_ptr<AtspiAccessible> getParent(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- Optional<size_t> getIndexInParent(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- std::shared_ptr<AtspiSelection> getSelectionInterface(const std::shared_ptr<AtspiAccessible> &accessibleObj) const;
- bool selectChild(const std::shared_ptr<AtspiSelection> &accessibleObj, size_t index) const;
+ ADD_INTROSPECTION_FUNCTIONS(Accessible, ACCESSIBLE);
+ ADD_INTROSPECTION_FUNCTIONS(Action, ACTION);
+ ADD_INTROSPECTION_FUNCTIONS(Selection, SELECTION);
+ ADD_INTROSPECTION_FUNCTIONS(Collection, COLLECTION);
+ ADD_INTROSPECTION_FUNCTIONS(Value, VALUE);
+ ADD_INTROSPECTION_FUNCTIONS(EditableText, EDITABLE_TEXT);
+#undef ADD_INTROSPECTION_FUNCTIONS
private:
bool ConnectAtClient();
efl::eldbus::eldbus_init eldbus;
efl::eldbus::connection connection;
+ EldbusConnectionCallbackHandle eldbusConnection;
+ template <typename T> DBus getProxy(const std::shared_ptr<T> &obj, const std::string &interface) const;
+ template <typename T> void getInterface(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<std::shared_ptr<T>> callback) const;
+ void getInterface(const AtspiAccessiblePtr &accessibleObj, AsyncCallback<AtspiAccessiblePtr> callback) const
+ {
+ callback(accessibleObj);
+ }
};
#endif
--- /dev/null
+#include "DBus.hpp"
+#include <sstream>
+#include "Atspi.hpp"
+#include "Singleton.hpp"
+
+unsigned int detail::CallId::LastId = 0;
+
+DBus::DBus()
+{
+}
+
+static EldbusConnectionCallbackHandle getConnectionByType(DBus::ConnectionType connectionType)
+{
+ switch (connectionType) {
+ case DBus::ConnectionType::SYSTEM:
+ return { eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM), eldbus_connection_unref };
+ case DBus::ConnectionType::SESSION:
+ return { eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION), eldbus_connection_unref };
+ default:
+ ASSERT(0);
+ }
+ return {};
+}
+
+DBus::DBus(std::string bus_name, std::string path_name, std::string interface_name, ConnectionType tp) :
+ DBus(std::move(bus_name), std::move(path_name), std::move(interface_name), getConnectionByType(tp))
+{
+}
+
+DBus::DBus(std::string bus_name, std::string path_name, std::string interface_name, const EldbusConnectionCallbackHandle &conn)
+{
+ if (!conn)
+ connectionState.connection = getConnectionByType(DBus::ConnectionType::SESSION);
+ else
+ connectionState.connection = conn;
+
+ std::ostringstream o;
+ o << "bus = " << bus_name << " path = " << path_name << " connection = " <<
+ eldbus_connection_unique_name_get(connectionState.connection.get());
+ if (interface_name != DBUS_INTERFACE_PROPERTIES)
+ o << " iname = " << interface_name;
+ info = o.str();
+ connectionState.object = { eldbus_object_get(connectionState.connection.get(), bus_name.c_str(), path_name.c_str()), eldbus_object_unref };
+ if (connectionState.object) {
+ connectionState.proxy = { eldbus_proxy_get(connectionState.object.get(), interface_name.c_str()), eldbus_proxy_unref };
+ }
+}
+
+DBus::~DBus()
+{
+ for (auto &p : callbacks)
+ delete p;
+}
+
+bool detail::signature<std::shared_ptr<AtspiAccessible>>::get(Eldbus_Message_Iter *iter, AtspiAccessiblePtr &v)
+{
+ subtype s;
+ if (!signature<subtype>::get(iter, s)) return false;
+ v = Singleton<Atspi>::instance().make(s.first.c_str(), s.second.c_str());
+ return true;
+}
--- /dev/null
+#ifndef DBUS_HPP
+#define DBUS_HPP
+
+#include <Eldbus.h>
+#include <memory>
+
+#include "Optional.hpp"
+#include <atspi/atspi.h>
+#include <cstdint>
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <map>
+#include <array>
+
+namespace detail
+{
+ struct caller_eldbus_connection_unref {
+ void operator()(Eldbus_Connection *p) const
+ {
+ eldbus_connection_unref(p);
+ }
+ };
+
+ struct caller_eldbus_message_unref {
+ void operator()(Eldbus_Message *p) const
+ {
+ eldbus_message_unref(p);
+ }
+ };
+
+ struct caller_eldbus_object_unref {
+ void operator()(Eldbus_Object *p) const
+ {
+ eldbus_object_unref(p);
+ }
+ };
+
+ struct caller_eldbus_proxy_unref {
+ void operator()(Eldbus_Proxy *p) const
+ {
+ eldbus_proxy_unref(p);
+ }
+ };
+}
+
+template <typename A> struct EldbusVariant {
+ A value;
+};
+
+using EldbusConnectionCallbackHandle = std::shared_ptr<Eldbus_Connection>;
+using EldbusMessageCallbackHandle = std::unique_ptr<Eldbus_Message, detail::caller_eldbus_message_unref>;
+using EldbusObjectCallbackHandle = std::shared_ptr<Eldbus_Object>;
+using EldbusProxyCallbackHandle = std::shared_ptr<Eldbus_Proxy>;
+
+namespace detail
+{
+ template <typename T, typename = void> struct signature;
+ template <typename ... ARGS> struct signature<std::tuple<ARGS...>>;
+ template <typename A, typename B> struct signature<std::pair<A, B>>;
+ template <typename A> struct signature<std::vector<A>>;
+ template <typename A, typename B> struct signature<std::vector<std::pair<A, B>>>;
+ template <typename A, size_t N> struct signature<std::array<A, N>>;
+ template <typename A, typename B, size_t N> struct signature<std::array<std::pair<A, B>, N>>;
+ template <typename A, typename B> struct signature<std::unordered_map<A, B>>;
+ template <typename A, typename B> struct signature<std::map<A, B>>;
+
+ template <typename T> struct signature<T, typename std::enable_if<std::is_enum<T>::value, void>::type> {
+ static std::string sig()
+ {
+ return "i";
+ }
+ static void set(Eldbus_Message_Iter *iter, T v)
+ {
+ // TODO: add check for failure in marshalling arguments
+
+ eldbus_message_iter_arguments_append(iter, sig().c_str(), (int)v);
+ }
+ static bool get(Eldbus_Message_Iter *iter, T &v)
+ {
+ int q;
+ auto z = eldbus_message_iter_get_and_next(iter, sig()[0], &q);
+ v = (T)q;
+ return z;
+ }
+ };
+
+#define SIGNATURE(T, S) \
+ template <> struct signature<T> { \
+ static std::string sig() { return #S; } \
+ static void set(Eldbus_Message_Iter *iter, T v) { \
+ eldbus_message_iter_arguments_append(iter, sig().c_str(), v); \
+ } \
+ static bool get(Eldbus_Message_Iter *iter, T &v) { \
+ return eldbus_message_iter_get_and_next(iter, sig()[0], &v); \
+ } \
+ };
+ SIGNATURE(uint8_t, y);
+ SIGNATURE(uint16_t, q);
+ SIGNATURE(uint32_t, u);
+ SIGNATURE(uint64_t, t);
+ SIGNATURE(int16_t, n);
+ SIGNATURE(int32_t, i);
+ SIGNATURE(int64_t, x);
+ SIGNATURE(double, d);
+#undef SIGNATURE
+
+ template <> struct signature<bool> {
+ static std::string sig()
+ {
+ return "b";
+ }
+ static void set(Eldbus_Message_Iter *iter, bool v)
+ {
+ eldbus_message_iter_arguments_append(iter, sig().c_str(), v ? 1 : 0);
+ }
+ static bool get(Eldbus_Message_Iter *iter, bool &v)
+ {
+ unsigned char q;
+ auto z = eldbus_message_iter_get_and_next(iter, sig()[0], &q);
+ v = q != 0;
+ return z;
+ }
+ };
+ template <> struct signature<std::string> {
+ static std::string sig()
+ {
+ return "s";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::string &v)
+ {
+ eldbus_message_iter_arguments_append(iter, sig().c_str(), v.c_str());
+ }
+ static void set(Eldbus_Message_Iter *iter, const char *v)
+ {
+ eldbus_message_iter_arguments_append(iter, sig().c_str(), v);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::string &v)
+ {
+ const char *q;
+ if (!eldbus_message_iter_get_and_next(iter, 's', &q)) {
+ if (!eldbus_message_iter_get_and_next(iter, 'o', &q))
+ return false;
+ }
+ v = q;
+ return true;
+ }
+ };
+ template <size_t INDEX, typename A, typename ... ARGS> struct signature_tuple_element_type_helper {
+ using type = typename signature_tuple_element_type_helper < INDEX - 1, ARGS... >::type;
+ };
+ template <typename A, typename ... ARGS> struct signature_tuple_element_type_helper<0, A, ARGS...> {
+ using type = A;
+ };
+
+ template <size_t INDEX, size_t SIZE, typename ... ARGS> struct signature_tuple_helper {
+ using current_type = typename signature_tuple_element_type_helper<INDEX, ARGS...>::type;
+
+ static std::string sig()
+ {
+ return signature<current_type>::sig() + signature_tuple_helper < INDEX + 1, SIZE, ARGS... >::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::tuple<ARGS...> &args)
+ {
+ signature<current_type>::set(iter, std::get<INDEX>(args));
+ signature_tuple_helper < INDEX + 1, SIZE, ARGS... >::set(iter, args);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &args)
+ {
+ return signature<current_type>::get(iter, std::get<INDEX>(args)) &&
+ signature_tuple_helper < INDEX + 1, SIZE, ARGS... >::get(iter, args);
+ }
+ };
+ template <size_t SIZE, typename ... ARGS> struct signature_tuple_helper<SIZE, SIZE, ARGS...> {
+ static std::string sig()
+ {
+ return "";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::tuple<ARGS...> &args)
+ {
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &args)
+ {
+ return true;
+ }
+ };
+ template <typename ... ARGS> struct signature<std::tuple<ARGS...>> {
+ static std::string sig()
+ {
+ return "(" + signature_tuple_helper<0, sizeof...(ARGS), ARGS...>::sig() + ")";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::tuple<ARGS...> &args)
+ {
+ auto entry = eldbus_message_iter_container_new(iter, 'r', NULL);
+ signature_tuple_helper<0, sizeof...(ARGS), ARGS...>::set(entry, args);
+ eldbus_message_iter_container_close(iter, entry);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &args)
+ {
+ Eldbus_Message_Iter *entry;
+ if (!eldbus_message_iter_get_and_next(iter, 'r', &entry)) return false;
+ auto z = signature_tuple_helper<0, sizeof...(ARGS), ARGS...>::get(entry, args);
+ eldbus_message_iter_container_close(iter, entry);
+ return z;
+ }
+ };
+ template <typename A, typename B> struct signature<std::pair<A, B>> {
+ static std::string sig()
+ {
+ return "(" + signature_tuple_helper<0, 2, A, B>::sig() + ")";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::pair<A, B> &ab, char sg = 'r')
+ {
+ auto entry = eldbus_message_iter_container_new(iter, sg, NULL);
+ signature_tuple_helper<0, 2, A, B>::set(entry, ab);
+ eldbus_message_iter_container_close(iter, entry);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::pair<A, B> &ab, char sg = 'r')
+ {
+ Eldbus_Message_Iter *entry;
+ if (!eldbus_message_iter_get_and_next(iter, sg, &entry)) return false;
+ std::tuple<A, B> ab_tmp;
+ auto z = signature_tuple_helper<0, 2, A, B>::get(entry, ab_tmp);
+ if (z) {
+ ab.first = std::move(std::get<0>(ab_tmp));
+ ab.second = std::move(std::get<1>(ab_tmp));
+ }
+ eldbus_message_iter_container_close(iter, entry);
+ return z;
+ }
+ };
+ template <typename A> struct signature<std::vector<A>> {
+ static std::string sig()
+ {
+ return "a" + signature<A>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::vector<A> &v)
+ {
+ auto lst = eldbus_message_iter_container_new(iter, 'a', signature<A>::sig().c_str());
+ ASSERT(lst);
+ for (auto &a : v) {
+ signature<A>::set(lst, a);
+ }
+ eldbus_message_iter_container_close(iter, lst);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::vector<A> &v)
+ {
+ Eldbus_Message_Iter *s;
+ v.clear();
+ if (!eldbus_message_iter_get_and_next(iter, 'a', &s)) return false;
+ A a;
+ while (signature<A>::get(s, a))
+ v.push_back(std::move(a));
+ return true;
+ }
+ };
+ template <typename A, size_t N> struct signature<std::array<A, N>> {
+ static std::string sig()
+ {
+ return "a" + signature<A>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::array<A, N> &v)
+ {
+ auto lst = eldbus_message_iter_container_new(iter, 'a', signature<A>::sig().c_str());
+ assert(lst);
+ for (auto &a : v) {
+ signature<A>::set(lst, a);
+ }
+ eldbus_message_iter_container_close(iter, lst);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::array<A, N> &v)
+ {
+ Eldbus_Message_Iter *s;
+ if (!eldbus_message_iter_get_and_next(iter, 'a', &s))
+ return false;
+ for (auto &a : v) {
+ if (!signature<A>::get(s, a))
+ return false;
+ }
+ return true;
+ }
+ };
+ template <typename A, typename B, size_t N> struct signature<std::array<std::pair<A, B>, N>> {
+ static std::string sig()
+ {
+ return "a" + signature<std::pair<A, B>>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::array<std::pair<A, B>, N> &v)
+ {
+ auto lst = eldbus_message_iter_container_new(iter, 'a', signature<std::pair<A, B>>::sig().c_str());
+ assert(lst);
+ for (auto &a : v) {
+ signature<std::pair<A, B>>::set(lst, a);
+ }
+ eldbus_message_iter_container_close(iter, lst);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::array<std::pair<A, B>, N> &v)
+ {
+ Eldbus_Message_Iter *s;
+ char sig = 'r';
+ if (!eldbus_message_iter_get_and_next(iter, 'a', &s)) return false;
+ char *t = eldbus_message_iter_signature_get(s);
+ if (t && t[0] == '{')
+ sig = '{';
+ free(t);
+ for (auto &a : v) {
+ if (!signature<std::pair<A, B>>::get(s, a, sig))
+ return false;
+ }
+ return true;
+ }
+ };
+ template <typename A, typename B> struct signature<std::vector<std::pair<A, B>>> {
+ static std::string sig()
+ {
+ return "a" + signature<std::pair<A, B>>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::vector<std::pair<A, B>> &v)
+ {
+ auto lst = eldbus_message_iter_container_new(iter, 'a', signature<std::pair<A, B>>::sig().c_str());
+ ASSERT(lst);
+ for (auto &a : v) {
+ signature<std::pair<A, B>>::set(lst, a);
+ }
+ eldbus_message_iter_container_close(iter, lst);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::vector<std::pair<A, B>> &v)
+ {
+ Eldbus_Message_Iter *s;
+ v.clear();
+ char sig = 'r';
+ if (!eldbus_message_iter_get_and_next(iter, 'a', &s)) return false;
+ char *t = eldbus_message_iter_signature_get(s);
+
+ // TODO: move handling of std::pair special case involing '{' to signature<std::pair<*, *>>
+ if (t && t[0] == '{')
+ sig = '{';
+ free(t);
+ std::pair<A, B> a;
+ while (signature<std::pair<A, B>>::get(s, a))
+ v.push_back(std::move(a));
+ return true;
+ }
+ };
+ template <typename A> struct signature<EldbusVariant<A>> {
+ static std::string sig()
+ {
+ return "v";
+ }
+ static void set(Eldbus_Message_Iter *iter, const EldbusVariant<A> &v)
+ {
+ set(iter, v.value);
+ }
+ static void set(Eldbus_Message_Iter *iter, const A &v)
+ {
+ auto var = eldbus_message_iter_container_new(iter, 'v', signature<A>::sig().c_str());
+ signature<A>::set(var, v.value);
+ eldbus_message_iter_container_close(iter, var);
+ }
+ static bool get(Eldbus_Message_Iter *iter, EldbusVariant<A> &v)
+ {
+ Eldbus_Message_Iter *s;
+ if (!eldbus_message_iter_get_and_next(iter, 'v', &s)) return false;
+ return signature<A>::get(s, v.value);
+ }
+ };
+ template <typename A, typename B> struct signature<std::unordered_map<A, B>> {
+ static std::string sig()
+ {
+ return "a{" + signature_tuple_helper<0, 2, A, B>::sig() + "}";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::unordered_map<A, B> &v)
+ {
+ auto sig = "{" + signature_tuple_helper<0, 2, A, B>::sig() + "}";
+ auto lst = eldbus_message_iter_container_new(iter, 'a', sig.c_str());
+ assert(lst);
+ for (auto &a : v) {
+ signature<std::pair<A, B>>::set(lst, a, 'e');
+ }
+ eldbus_message_iter_container_close(iter, lst);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::unordered_map<A, B> &v)
+ {
+ Eldbus_Message_Iter *s;
+ v.clear();
+ if (!eldbus_message_iter_get_and_next(iter, 'a', &s)) return false;
+ std::pair<A, B> a;
+ while (signature<std::pair<A, B>>::get(s, a))
+ v.insert(std::move(a));
+ return true;
+ }
+ };
+ template <typename A, typename B> struct signature<std::map<A, B>> {
+ static std::string sig()
+ {
+ return "a{" + signature_tuple_helper<0, 2, A, B>::sig() + "}";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::map<A, B> &v)
+ {
+ auto sig = "{" + signature_tuple_helper<0, 2, A, B>::sig() + "}";
+ auto lst = eldbus_message_iter_container_new(iter, 'a', sig.c_str());
+ assert(lst);
+ for (auto &a : v) {
+ signature<std::pair<A, B>>::set(lst, a, 'e');
+ }
+ eldbus_message_iter_container_close(iter, lst);
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::map<A, B> &v)
+ {
+ Eldbus_Message_Iter *s;
+ v.clear();
+ if (!eldbus_message_iter_get_and_next(iter, 'a', &s)) return false;
+ std::pair<A, B> a;
+ while (signature<A>::get(s, a))
+ v.insert(std::move(a));
+ return true;
+ }
+ };
+ template <typename A> struct signature<const A &> {
+ static std::string sig()
+ {
+ return signature<A>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const A &v)
+ {
+ signature<A>::set(iter, v);
+ }
+ static void get(Eldbus_Message_Iter *iter, A &v)
+ {
+ signature<A>::get(iter, v);
+ }
+ };
+ template <typename A> struct signature<A &> {
+ static std::string sig()
+ {
+ return signature<A>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const A &v)
+ {
+ signature<A>::set(iter, v);
+ }
+ static void get(Eldbus_Message_Iter *iter, A &v)
+ {
+ signature<A>::get(iter, v);
+ }
+ };
+ template <typename A> struct signature<const A> {
+ static std::string sig()
+ {
+ return signature<A>::sig();
+ }
+ static void set(Eldbus_Message_Iter *iter, const A &v)
+ {
+ signature<A>::set(iter, v);
+ }
+ static void get(Eldbus_Message_Iter *iter, A &v)
+ {
+ signature<A>::get(iter, v);
+ }
+ };
+ template <> struct signature<std::shared_ptr<AtspiAccessible>> {
+ using subtype = std::pair<std::string, std::string>;
+
+ static std::string sig()
+ {
+ return "(so)";
+ }
+ static void set(Eldbus_Message_Iter *iter, const std::shared_ptr<AtspiAccessible> &v)
+ {
+ const auto prefixPath = "/org/a11y/atspi/accessible/";
+ const auto nullPath = "/org/a11y/atspi/null";
+
+ if (v) {
+ auto bus = atspi_accessible_get_bus_name(v.get(), NULL);
+ auto path = atspi_accessible_get_path(v.get(), NULL);
+ signature<subtype>::set(iter, { bus, std::string{prefixPath} + path });
+ g_free(path);
+ g_free(bus);
+ } else {
+ signature<subtype>::set(iter, { {}, std::string{nullPath} });
+ }
+ }
+ static bool get(Eldbus_Message_Iter *iter, std::shared_ptr<AtspiAccessible> &v);
+ };
+ struct CallId {
+ static unsigned int LastId;
+ unsigned int id = ++LastId;
+ };
+ template <typename R> struct unpackValues_Helper {
+ bool operator()(CallId callId, R &r, const Eldbus_Message *msg) const
+ {
+ auto iter = eldbus_message_iter_get(msg);
+
+ if (iter) {
+ if (signature<R>::get(iter, r))
+ return true;
+ ERROR("call %d: signature mismatch, got %s, expected %s",
+ callId.id,
+ eldbus_message_signature_get(msg),
+ signature<R>::sig().c_str());
+ } else
+ ERROR("call %d: failed to get iter", callId.id);
+ return false;
+ }
+ };
+ template <typename ...ARGS> struct unpackValues_Helper<std::tuple<ARGS...>> {
+ bool operator()(CallId callId, std::tuple<ARGS...> &r, const Eldbus_Message *msg) const
+ {
+ auto iter = eldbus_message_iter_get(msg);
+ if (iter) {
+ if (signature_tuple_helper<0, sizeof...(ARGS), ARGS...>::get(iter, r))
+ return true;
+ ERROR("call %d: signature mismatch, got %s, expected %s",
+ callId.id,
+ eldbus_message_signature_get(msg),
+ signature_tuple_helper<0, sizeof...(ARGS), ARGS...>::sig().c_str());
+ } else
+ ERROR("call %d: failed to get iter", callId.id);
+ return false;
+ }
+ };
+ template <typename R> bool unpackValues(CallId callId, R &r, const Eldbus_Message *msg)
+ {
+ return unpackValues_Helper<R>()(callId, r, msg);
+ }
+ template <typename R> void packValues(CallId callId, Eldbus_Message *msg, const R &r)
+ {
+ DEBUG("call %d: packing values with signature %s", callId.id, signature<R>::sig().c_str());
+ auto iter = eldbus_message_iter_get(msg);
+ signature<R>::set(iter, r);
+ DEBUG("call %d: signature is %s", callId.id, eldbus_message_signature_get(msg));
+ }
+ inline void packValues_helper(Eldbus_Message_Iter *iter) {}
+ template <typename A, typename ...ARGS> void packValues_helper(Eldbus_Message_Iter *iter, A &&a, ARGS &&... r)
+ {
+ signature<A>::set(iter, std::forward<A>(a));
+ packValues_helper(iter, std::forward<ARGS>(r)...);
+ }
+ template <typename ...ARGS> void packValues(CallId callId, Eldbus_Message *msg, ARGS &&... r)
+ {
+ DEBUG("call %d: packing values with signature %s", callId.id, signature_tuple_helper<0, sizeof...(ARGS), ARGS...>::sig().c_str());
+ auto iter = eldbus_message_iter_get(msg);
+ packValues_helper(iter, std::forward<ARGS>(r)...);
+ DEBUG("call %d: signature is %s", callId.id, eldbus_message_signature_get(msg));
+ }
+
+ template<int ...> struct seq {};
+ template<int N, int ...S> struct gens : gens < N - 1, N - 1, S... > {};
+ template<int ...S> struct gens<0, S...> {
+ typedef seq<S...> type;
+ };
+
+ template <typename C, typename R, typename ... ARGS> struct apply_helper {
+ const C &c;
+ const std::tuple<ARGS...> &args;
+
+ template<int ... S> R apply_2(seq<S...>)
+ {
+ return c(std::get<S>(args)...);
+ }
+ R apply_1()
+ {
+ return apply_2(typename gens<sizeof...(ARGS)>::type());
+ }
+ };
+ template <typename C, typename R, typename ... ARGS> R apply(const C &c, const std::tuple<ARGS...> &args)
+ {
+ apply_helper<C, R, ARGS...> ah { c, args };
+ return ah.apply_1();
+ }
+
+ struct EldbusProxyBase {
+ EldbusProxyBase()
+ {
+ eldbus_init();
+ }
+ ~EldbusProxyBase()
+ {
+ eldbus_shutdown();
+ }
+ };
+}
+
+namespace detail
+{
+ template <typename Q> struct Method;
+ template <typename R, typename ... ARGS> struct Method<R(ARGS...)>;
+ template <typename ... ARGS> struct Method<void(ARGS...)>;
+ template <typename Q> struct Listen;
+ template <typename ... ARGS> struct Listen<void(ARGS...)>;
+
+ constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
+
+ struct ConnectionState {
+ EldbusConnectionCallbackHandle connection;
+ EldbusObjectCallbackHandle object;
+ EldbusProxyCallbackHandle proxy;
+ };
+ static void callAsyncCb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
+ {
+ auto d = (std::pair<CallId, std::function<void(const Eldbus_Message *)>> *)data;
+ DEBUG("call %d: got reply", d->first.id);
+ d->second(msg);
+ }
+ static void pendingFreeCb(void *data, const void *)
+ {
+ auto d = (std::pair<CallId, std::function<void(const Eldbus_Message *)>> *)data;
+ DEBUG("call %d: deleting", d->first.id);
+ delete d;
+ }
+ template <typename ... ARGS>
+ EldbusMessageCallbackHandle call(CallId callId, ConnectionState &connectionState, const std::string &func_name, const ARGS &... args)
+ {
+ if (!connectionState.proxy) {
+ DEBUG("call %d: not initialized", callId.id);
+ return {};
+ }
+
+ DEBUG("call %d: calling '%s'", callId.id, func_name.c_str());
+ EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new(connectionState.proxy.get(), func_name.c_str())};
+ if (!msg) {
+ DEBUG("call %d: failed", callId.id);
+ return {};
+ }
+
+ detail::packValues(callId, msg.get(), args...);
+ auto replyRawPtr = eldbus_proxy_send_and_block(connectionState.proxy.get(), msg.release(), ELDBUS_CALL_TIMEOUT);
+ EldbusMessageCallbackHandle reply{ replyRawPtr };
+ DEBUG("call %d: calling '%s' done", callId.id, func_name.c_str());
+ if (!reply) {
+ DEBUG("call %d: failed", callId.id);
+ return {};
+ }
+ const char *errname, *errmsg;
+ if (eldbus_message_error_get(reply.get(), &errname, &errmsg)) {
+ DEBUG("call %d: %s: %s", callId.id, errname, errmsg);
+ return {};
+ }
+ DEBUG("call %d: got reply with signature '%s'", callId.id, eldbus_message_signature_get(reply.get()));
+ return reply;
+ }
+
+ template <typename ... ARGS>
+ void asyncCall(CallId callId, ConnectionState connectionState, const std::string &func_name,
+ std::function<void(const Eldbus_Message *)> callback, const ARGS &... args)
+ {
+ if (!connectionState.proxy) {
+ DEBUG("call %d: not initialized", callId.id);
+ callback({});
+ return;
+ }
+
+ EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new(connectionState.proxy.get(), func_name.c_str())};
+ if (!msg) {
+ DEBUG("call %d: failed", callId.id);
+ callback({});
+ return;
+ }
+
+ auto cbData = new std::pair<CallId, std::function<void(const Eldbus_Message *)>> {
+ callId, [callback, connectionState, callId](const Eldbus_Message * reply)
+ {
+ DEBUG("call %d: calling done", callId.id);
+ if (!reply)
+ DEBUG("call %d: failed", callId.id);
+ else {
+ const char *errname, *errmsg;
+ if (eldbus_message_error_get(reply, &errname, &errmsg)) {
+ DEBUG("call %d: %s: %s", callId.id, errname, errmsg);
+ reply = nullptr;
+ } else
+ DEBUG("call %d: got reply with signature '%s'", callId.id, eldbus_message_signature_get(reply));
+ }
+ callback(reply);
+ }
+ };
+
+ detail::packValues(callId, msg.get(), args...);
+ auto pending = eldbus_proxy_send(connectionState.proxy.get(), msg.release(), callAsyncCb, cbData, ELDBUS_CALL_TIMEOUT);
+ if (pending)
+ eldbus_pending_free_cb_add(pending, pendingFreeCb, cbData);
+ else {
+ DEBUG("call %d: sending failed", callId.id);
+ delete cbData;
+ callback({});
+ return;
+ }
+ DEBUG("call %d: call sent", callId.id);
+ }
+ static void listenerCallback(void *data, const Eldbus_Message *msg)
+ {
+ (*((std::function<void(const Eldbus_Message *msg)> *)data))(msg);
+ }
+ template <typename ... ARGS> void addListener(CallId callId, ConnectionState &connectionState,
+ const std::string &func_name,
+ std::vector<std::function<void(const Eldbus_Message *msg)>*> &callbacks,
+ std::function<void(ARGS...)> callback)
+ {
+ auto tmp = new std::function<void(const Eldbus_Message *msg)> {
+ [ callId, connectionState, callback ](const Eldbus_Message * msg) -> void {
+ const char *errname, *aux;
+ if (eldbus_message_error_get(msg, &errname, &aux))
+ {
+ ERROR("call %d: Eldbus error: %s %s", callId.id, errname, aux);
+ return;
+ }
+
+ DEBUG("call %d: received signal with signature '%s'", callId.id, eldbus_message_signature_get(msg));
+ std::tuple<ARGS...> params;
+ if (detail::unpackValues(callId, params, msg))
+ detail::apply<std::function<void(ARGS...)>, void, ARGS...>(callback, params);
+ }
+ };
+ eldbus_proxy_signal_handler_add(connectionState.proxy.get(), func_name.c_str(), listenerCallback, std::move(tmp));
+ callbacks.push_back(tmp);
+ }
+ template <typename ... ARGS>
+ void displayDebugCallInfo(CallId callId, const std::string &func_name, const std::string &info, const ARGS &...)
+ {
+ DEBUG("call %d: %s fname = %s", callId, info.c_str(), func_name.c_str());
+ }
+ template <typename ... ARGS>
+ void displayDebugCallInfo(CallId callId, const std::string &func_name, std::string info, std::string a, const std::string &b, const ARGS &...)
+ {
+ if (func_name == "Get" && info.find(" iname = ") == std::string::npos)
+ DEBUG("call %d: %s iname = %s pname = %s", callId, info.c_str(), a.c_str(), b.c_str());
+ else
+ displayDebugCallInfo(callId, func_name, info);
+ }
+}
+
+class DBus : private detail::EldbusProxyBase
+{
+public:
+ enum class ConnectionType {
+ SYSTEM, SESSION
+ };
+ DBus();
+ DBus(std::string bus_name, std::string path_name, std::string interface_name,
+ ConnectionType tp);
+ DBus(std::string bus_name, std::string path_name, std::string interface_name,
+ const EldbusConnectionCallbackHandle &conn = {});
+ ~DBus();
+
+ DBus(const DBus &) = default;
+ DBus(DBus &&) = default;
+
+ DBus &operator = (DBus &&) = default;
+ DBus &operator = (const DBus &) = default;
+
+ explicit operator bool () const
+ {
+ return bool(connectionState.proxy);
+ }
+
+ template <typename Q> using Method = detail::Method<Q>;
+ template <typename Q> using Listen = detail::Listen<Q>;
+
+ template <typename R>
+ Method<R> method(std::string func_name)
+ {
+ return Method<R> { connectionState, std::move(func_name), info };
+ }
+
+ template <typename R>
+ Listen<R> listen(std::string func_name)
+ {
+ return Listen<R> { connectionState, callbacks, std::move(func_name), info };
+ }
+
+private:
+ detail::ConnectionState connectionState;
+ std::vector<std::function<void(const Eldbus_Message *)>*> callbacks;
+ std::string info;
+};
+
+template <typename RetType, typename ... ARGS> struct detail::Method<RetType(ARGS...)> {
+ ConnectionState connectionState;
+ std::string func_name;
+ std::string info;
+
+ Optional<RetType> call(const ARGS &... args)
+ {
+ CallId callId;
+ detail::displayDebugCallInfo(callId, func_name, info, args...);
+ auto reply = detail::call(callId, connectionState, func_name, args...);
+ if (reply) {
+ RetType r;
+ if (detail::unpackValues<RetType>(callId, r, reply.get()))
+ return r;
+ }
+ return {};
+ }
+ void asyncCall(const ARGS &... args, std::function<void(Optional<RetType>)> callback)
+ {
+ CallId callId;
+ detail::displayDebugCallInfo(callId, func_name, info, args...);
+ auto connectionState = this->connectionState;
+ auto fn = func_name;
+ auto cc = [callId, connectionState, callback](const Eldbus_Message * reply) {
+ DEBUG("call %d: processing asynchronous reply (%d)", callId.id, reply ? 1 : 0);
+ if (!reply)
+ callback({});
+ else {
+ RetType r;
+ if (!detail::unpackValues<RetType>(callId, r, reply))
+ callback({});
+ else
+ callback(r);
+ }
+ DEBUG("call %d: processing asynchronous reply done", callId.id);
+ };
+ detail::asyncCall(callId, connectionState, func_name, std::move(cc), args...);
+ }
+};
+template <typename ... ARGS> struct detail::Method<void(ARGS...)> {
+ ConnectionState connectionState;
+ std::string func_name;
+ std::string info;
+
+ bool call(const ARGS &... args)
+ {
+ CallId callId;
+ detail::displayDebugCallInfo(callId, func_name, info, args...);
+ auto reply = detail::call(callId, connectionState, func_name, args...);
+ return bool(reply);
+ }
+ void asyncCall(const ARGS &... args, std::function<void(bool)> callback)
+ {
+ CallId callId;
+ detail::displayDebugCallInfo(callId, func_name, info, args...);
+ auto connectionState = this->connectionState;
+ auto fn = func_name;
+ auto cc = [callId, connectionState, callback](const Eldbus_Message * reply) {
+ DEBUG("call %d: processing asynchronous reply", callId.id);
+ if (!reply)
+ callback(false);
+ else {
+ callback(true);
+ }
+ DEBUG("call %d: processing asynchronous reply done", callId.id);
+ };
+ detail::asyncCall(callId, connectionState, func_name, std::move(cc), args...);
+ }
+};
+template <typename ... ARGS> struct detail::Listen<void(ARGS...)> {
+ detail::ConnectionState connectionState;
+ std::vector<std::function<void(const Eldbus_Message *)>*> &callbacks;
+ std::string func_name;
+ std::string info;
+
+ void add(std::function<void(ARGS...)> cc)
+ {
+ CallId callId;
+ detail::displayDebugCallInfo(callId, func_name, info);
+ detail::addListener<ARGS...>(callId, connectionState, func_name, callbacks, std::move(cc));
+ }
+};
+
+#endif
#include "UniversalSwitchLog.hpp"
#include "Atspi.hpp"
#include "UIElement.hpp"
+#include "DBus.hpp"
#include <glib.h>
#include <glib-object.h>
#include <memory>
#include <functional>
-constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
+using AtspiAccessiblePtr = std::shared_ptr<AtspiAccessible>;
NavigationInterface::~NavigationInterface()
{
}
}
-struct caller_eldbus_connection_unref {
- void operator()(Eldbus_Connection *p) const
- {
- eldbus_connection_unref(p);
- }
-};
-
-struct caller_eldbus_message_unref {
- void operator()(Eldbus_Message *p) const
- {
- eldbus_message_unref(p);
- }
-};
-
-struct caller_eldbus_object_unref {
- void operator()(Eldbus_Object *p) const
- {
- eldbus_object_unref(p);
- }
-};
-
-struct caller_eldbus_proxy_unref {
- void operator()(Eldbus_Proxy *p) const
- {
- eldbus_proxy_unref(p);
- }
-};
-
-using EldbusConnectionCallbackHandle = std::unique_ptr<Eldbus_Connection, caller_eldbus_connection_unref>;
-using EldbusMessageCallbackHandle = std::unique_ptr<Eldbus_Message, caller_eldbus_message_unref>;
-using EldbusObjectCallbackHandle = std::unique_ptr<Eldbus_Object, caller_eldbus_object_unref>;
-using EldbusProxyCallbackHandle = std::unique_ptr<Eldbus_Proxy, caller_eldbus_proxy_unref>;
-using AtspiAccessiblePtr = std::shared_ptr<AtspiAccessible>;
-
-namespace
-{
- void eldbusParamSet(const EldbusMessageCallbackHandle &msg)
- {}
-
- void eldbusParamSet(const EldbusMessageCallbackHandle &msg, int arg)
- {
- eldbus_message_arguments_append(msg.get(), "i", arg);
- }
-
- template <typename A, typename ... ARGS>
- void eldbusParamSet(const EldbusMessageCallbackHandle &msg, A &&arg, ARGS &&... args)
- {
- eldbusParamSet(msg, std::forward<A>(arg));
- eldbusParamSet(msg, std::forward<ARGS>(args)...);
- }
-
- bool eldbusParamGet(Eldbus_Message_Iter *iter, int &v)
- {
- return eldbus_message_iter_get_and_next(iter, 'i', &v);
- }
-
- bool eldbusParamGet(Eldbus_Message_Iter *iter, AtspiAccessiblePtr &v)
- {
- char *busname, *path;
- if (!eldbus_message_iter_get_and_next(iter, 's', &path)) return false;
- if (!eldbus_message_iter_get_and_next(iter, 's', &busname)) return false;
- if (!path || !busname) return false;
- if (!*path || !*busname) {
- v = {};
- return true;
- }
- auto ptr = ref_accessible(busname, (std::string("/org/a11y/atspi/accessible/") + path).c_str());
- v = AtspiAccessiblePtr{ ptr, g_object_unref };
- return true;
- }
-
- bool eldbusParamGet(Eldbus_Message_Iter *iter, std::string &v)
- {
- char *t;
- if (!eldbus_message_iter_get_and_next(iter, 's', &t)) return false;
- v = t;
- return true;
- }
-
- bool eldbusParamGet(Eldbus_Message_Iter *iter, std::tuple<> &)
- {
- Eldbus_Message_Iter *s;
- if (!eldbus_message_iter_get_and_next(iter, 'r', &s)) return false;
- return true;
- }
-
- template <typename A, typename B> bool eldbusParamGet(Eldbus_Message_Iter *iter, std::pair<A, B> &v);
- template <typename ... ARGS> bool eldbusParamGet(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &v);
- template <typename A> bool eldbusParamGet(Eldbus_Message_Iter *iter, std::vector<A> &v);
-
- template <typename T>
- typename std::enable_if<std::is_enum<T>::value, bool>::type eldbusParamGet(Eldbus_Message_Iter *iter, T &v)
- {
- int i;
- if (!eldbus_message_iter_get_and_next(iter, 'i', &i))
- return false;
- v = (T)i;
- return true;
- }
-
- template <int I, typename ... ARGS>
- struct EldbusParamGetTuple {
- static bool get(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &args)
- {
- if (!EldbusParamGetTuple < I - 1, ARGS... >::get(iter, args))
- return false;
- return eldbusParamGet(iter, std::get<I>(args));
- }
- };
-
- template <typename ... ARGS>
- struct EldbusParamGetTuple<0, ARGS...> {
- static bool get(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &args)
- {
- return eldbusParamGet(iter, std::get<0>(args));
- }
- };
-
- template <typename A, typename B> bool eldbusParamGet(Eldbus_Message_Iter *iter, std::pair<A, B> &v)
- {
- Eldbus_Message_Iter *s;
- if (!eldbus_message_iter_get_and_next(iter, 'r', &s)) return false;
- if (!eldbusParamGet(s, v.first)) return false;
- if (!eldbusParamGet(s, v.second)) return false;
- return true;
- }
-
- template <typename ... ARGS> bool eldbusParamGet(Eldbus_Message_Iter *iter, std::tuple<ARGS...> &v)
- {
- Eldbus_Message_Iter *s;
- if (!eldbus_message_iter_get_and_next(iter, 'r', &s)) return false;
- return EldbusParamGetTuple < sizeof...(ARGS) - 1, ARGS... >::get(s, v);
- }
-
- template <typename A> bool eldbusParamGet(Eldbus_Message_Iter *iter, std::vector<A> &v)
- {
- Eldbus_Message_Iter *s;
- if (!eldbus_message_iter_get_and_next(iter, 'a', &s)) return false;
- v.resize(0);
- while (true) {
- v.push_back(A{});
- if (!eldbusParamGet(s, v.back())) {
- v.pop_back();
- break;
- }
- }
- return true;
- }
-
- template <class A>
- bool eldbusParamGetFromMsg(const Eldbus_Message *msg, A &v)
- {
- auto iter = eldbus_message_iter_get(msg);
- return eldbusParamGet(iter, v);
- }
-
- template <typename ... ARGS>
- bool eldbusParamGetFromMsg(const Eldbus_Message *msg, std::tuple<ARGS...> &v)
- {
- auto iter = eldbus_message_iter_get(msg);
- return EldbusParamGetTuple < sizeof...(ARGS) - 1, ARGS... >::get(iter, v);
- }
-
- bool eldbusParamGetFromMsg(const Eldbus_Message *msg, std::tuple<> &v)
- {
- return true;
- }
-
- class EldbusInitializer
- {
- protected:
- EldbusInitializer()
- {
- if (eldbus_init() == 0) {
- ERROR("Unable to initialize eldbus module");
- }
- }
-
- ~EldbusInitializer()
- {
- eldbus_shutdown();
- }
- };
-
- template <typename A>
- Optional<A> eldbusParamsGet(const Eldbus_Message *msg)
- {
- A a;
- if (!eldbusParamGetFromMsg(msg, a)) return {};
- return std::move(a);
- }
-
- class EldbusProxy : public EldbusInitializer
- {
- public:
- EldbusProxy() = default;
-
- EldbusProxy(EldbusProxy &&) = default;
-
- EldbusProxy(std::string bus_name, std::string path_name, std::string interface_name, EldbusConnectionCallbackHandle conn = {})
- {
- if (!conn)
- conn.reset(eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION));
- connection = std::move(conn);
- if (connection) {
- object.reset(eldbus_object_get(connection.get(), bus_name.c_str(), path_name.c_str()));
- if (object) {
- proxy.reset(eldbus_proxy_get(object.get(), interface_name.c_str()));
- }
- }
- }
-
- EldbusProxy &operator = (EldbusProxy &&) = default;
-
- explicit operator bool () const
- {
- return bool(proxy);
- }
-
- template <typename R, typename ... ARGS>
- typename std::enable_if<std::is_same<void, R>::value, bool>::type call(const std::string &func_name, ARGS &&... args)
- {
- auto reply = _call(func_name, std::forward<ARGS>(args)...);
- return bool(reply);
- }
-
- template <typename R, typename ... ARGS>
- typename std::enable_if < !std::is_same<void, R>::value, Optional<R >>::type call(const std::string &func_name, ARGS &&... args)
- {
- auto reply = _call(func_name, std::forward<ARGS>(args)...);
- return eldbusParamsGet<R>(reply.get());
- }
-
- template <typename R, typename ... ARGS>
- void listen(const std::string &func_name, std::function<R(ARGS...)> fnc)
- {
- auto tmp = [ = ](const Eldbus_Message * msg) -> void {
- DEBUG("received signal '%s' '%s'", func_name.c_str(), eldbus_message_signature_get(msg));
- auto params = eldbusParamsGet<std::tuple<ARGS...>>(msg);
- if (!params)
- {
- ERROR("failed to parse arguments from msg with signature '%s'", eldbus_message_signature_get(msg));
- return;
- }
- _invoke(fnc, std::move(*params));
- };
- auto callback = new std::function<void(const Eldbus_Message *msg)>(std::move(tmp));
- eldbus_proxy_signal_handler_add(proxy.get(), func_name.c_str(), listener_callback, callback);
- }
-
- private:
- EldbusConnectionCallbackHandle connection;
- EldbusObjectCallbackHandle object;
- EldbusProxyCallbackHandle proxy;
-
- template <typename R>
- static R _invoke(std::function<R()> fnc, const std::tuple<> &t)
- {
- return fnc();
- }
-
- template <typename R, typename A1>
- static R _invoke(std::function<R(A1)> fnc, const std::tuple<A1> &t)
- {
- return fnc(std::get<0>(t));
- }
-
- template <typename R, typename A1, typename A2>
- static R _invoke(std::function<R(A1, A2)> fnc, const std::tuple<A1, A2> &t)
- {
- return fnc(std::get<0>(t), std::get<1>(t));
- }
-
- template <typename R, typename A1, typename A2, typename A3>
- static R _invoke(std::function<R(A1, A2, A3)> fnc, const std::tuple<A1, A2, A3> &t)
- {
- return fnc(std::get<0>(t), std::get<1>(t), std::get<2>(t));
- }
-
- template <typename R, typename A1, typename A2, typename A3, typename A4>
- static R _invoke(std::function<R(A1, A2, A3, A4)> fnc, const std::tuple<A1, A2, A3, A4> &t)
- {
- return fnc(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
- }
-
- template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
- static R _invoke(std::function<R(A1, A2, A3, A4, A5)> fnc, const std::tuple<A1, A2, A3, A4, A5> &t)
- {
- return fnc(std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t), std::get<4>(t));
- }
-
- static void listener_callback(void *data, const Eldbus_Message *msg)
- {
- (*((std::function<void(const Eldbus_Message *msg)> *)data))(msg);
- }
-
- template <typename ... ARGS>
- EldbusMessageCallbackHandle _call(const std::string &func_name, ARGS &&... args)
- {
- DEBUG("calling '%s'", func_name.c_str());
- EldbusMessageCallbackHandle msg{eldbus_proxy_method_call_new(proxy.get(), func_name.c_str())};
- if (!msg) {
- DEBUG("failed");
- return {};
- }
- eldbusParamSet(msg, std::forward<ARGS>(args)...);
- EldbusMessageCallbackHandle reply{eldbus_proxy_send_and_block(proxy.get(), msg.release(), ELDBUS_CALL_TIMEOUT)};
- DEBUG("calling '%s' done", func_name.c_str());
- if (!reply) {
- DEBUG("failed");
- return {};
- }
- const char *errname, *errmsg;
- if (eldbus_message_error_get(reply.get(), &errname, &errmsg)) {
- DEBUG("%s: %s", errname, errmsg);
- return {};
- }
- DEBUG("got reply with signature '%s'", eldbus_message_signature_get(reply.get()));
- return reply;
- }
- };
-}
-
void hack_setRootObjectAttributes(std::shared_ptr<AtspiAccessible> obj, std::vector<std::pair<std::string, std::string>> attrs);
class NavigationImpl : public NavigationInterface
public:
NavigationImpl()
{
- EldbusProxy proxy{"org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus"};
- auto addr = proxy.call<std::string>("GetAddress");
- if (!addr)
- ERROR("failed");
- else {
- EldbusConnectionCallbackHandle connection { eldbus_address_connection_get((*addr).c_str()) };
+ DBus proxy{"org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus"};
+ auto addr = proxy.method<std::string()>("GetAddress").call();
+ if (addr) {
+ DEBUG("got dbus %s", (*addr).c_str());
+ EldbusConnectionCallbackHandle connection { eldbus_address_connection_get((*addr).c_str()), eldbus_connection_unref };
navProxy = { "org.tizen.ScreenNavigator", "/org/tizen/ScreenNavigator", "org.tizen.ScreenNavigator", std::move(connection) };
}
return;
#define LISTEN(n) \
- do { navProxy.listen(#n, std::function<void()>([=]() { emitCallback(CallbackType::n); })); } while(0)
+ do { navProxy.listen<void()>(#n).add([=]() { emitCallback(CallbackType::n); }); } while (0)
LISTEN(FirstRow);
LISTEN(LastRow);
LISTEN(FirstElementInRow);
#undef LISTEN
#define LISTEN(n, SignalName) \
- do { navProxy.listen(SignalName, std::function<void()>([=]() { emitCallback(CallbackType::n); })); } while(0)
+ do { navProxy.listen<void()>(SignalName).add([=]() { emitCallback(CallbackType::n); }); } while (0)
LISTEN(DashedRow, "SpecialRow");
LISTEN(DashedElementInRow, "SpecialElementInRow");
#undef LISTEN
-
- navProxy.listen("ContextChanged", std::function<void(AtspiAccessiblePtr, int, int, int, int)>(
- [this](AtspiAccessiblePtr obj, int x, int y, int width, int height) {
- emitCallback(CallbackType::ContextChanged, std::make_shared<UIElement>(obj), x, y, width, height);
- }));
- navProxy.listen("BoxMoved", std::function<void(int, int, int, int, BoxPositionMode)>(
- [this](int x, int y, int w, int h, BoxPositionMode mode) {
+ navProxy.listen<void(AtspiAccessiblePtr)>("ContextChanged").add(
+ [ = ](AtspiAccessiblePtr obj) {
+ emitCallback(CallbackType::ContextChanged, std::make_shared<UIElement>(obj));
+ DEBUG("got element %s", Singleton<Atspi>::instance().getUniqueId(obj).c_str());
+ });
+ navProxy.listen<void(int, int, int, int, BoxPositionMode)>("BoxMoved").add(
+ [ = ](int x, int y, int w, int h, BoxPositionMode mode) {
emitCallback(CallbackType::BoxMoved, x, y, w, h, mode);
- }));
-
- navProxy.listen("HackAttributesForRootAfterContextChanged", std::function<void(AtspiAccessiblePtr, std::vector<std::pair<std::string, std::string>>)>(
- [this](AtspiAccessiblePtr root, std::vector<std::pair<std::string, std::string>> attrs) {
+ });
+ navProxy.listen<void(AtspiAccessiblePtr, std::vector<std::pair<std::string, std::string>>)>("HackAttributesForRootAfterContextChanged").add(
+ [ = ](AtspiAccessiblePtr root, std::vector<std::pair<std::string, std::string>> attrs) {
hack_setRootObjectAttributes(root, std::move(attrs));
- }));
+ });
+
}
~NavigationImpl() = default;
void resetPosition() override
{
- navProxy.call<void>("ResetIndexes");
+ navProxy.method<void()>("ResetIndexes").call();
}
void nextRow() override
{
- navProxy.call<void>("NextRow");
+ navProxy.method<void()>("NextRow").call();
}
void prevRow() override
{
- navProxy.call<void>("PreviousRow");
+ navProxy.method<void()>("PreviousRow").call();
}
void nextElementInRow() override
{
- navProxy.call<void>("NextElementInRow");
+ navProxy.method<void()>("NextElementInRow").call();
}
void prevElementInRow() override
{
- navProxy.call<void>("PreviousElementInRow");
+ navProxy.method<void()>("PreviousElementInRow").call();
}
std::shared_ptr<UIElement> getCurrentElement() override
{
- auto current = navProxy.call<AtspiAccessiblePtr>("GetCurrentElement");
+ auto current = navProxy.method<AtspiAccessiblePtr()>("GetCurrentElement").call();
return std::make_shared<UIElement>(std::move(*current));
}
std::shared_ptr<UIElement> getElementAtPoint(int x, int y) override
{
- auto elem = navProxy.call<AtspiAccessiblePtr>("GetElementAtPoint", x, y);
+ auto elem = navProxy.method<AtspiAccessiblePtr(int, int)>("GetElementAtPoint").call(x, y);
return std::make_shared<UIElement>(std::move(*elem), Point{x, y});
}
}
}
- EldbusProxy navProxy;
+ DBus navProxy;
};
template<>