#include "../NavigationInterface.hpp"
#include <mutex>
+#include <future>
#include <chrono>
#include <thread>
#include <fstream>
});
return std::move(result);
}
+ void findByName(const std::vector<AtspiAccessiblePtr> &elems, std::string requestedName, std::function<void(DBus::ValueOrError<std::vector<AtspiAccessiblePtr>>)> callback)
+ {
+ struct Exec {
+ std::function<void(DBus::ValueOrError<std::vector<AtspiAccessiblePtr>>)> callback;
+ std::string requestedName;
+ std::vector<AtspiAccessiblePtr> foundElements;
+ Optional<DBus::Error> error;
+
+ ~Exec()
+ {
+ if (error) callback(*error);
+ else callback(std::move(foundElements));
+ }
+ };
+ auto exec = std::make_shared<Exec>();
+ exec->callback = std::move(callback);
+ exec->requestedName = std::move(requestedName);
+ auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+ for (auto &e : elems) {
+ atspi->getName(e, [e, exec](DBus::ValueOrError<std::string> name) {
+ if (!name) {
+ if (!exec->error)
+ exec->error = name.getError();
+ } else if (std::get<0>(name) == exec->requestedName) {
+ exec->foundElements.push_back(e);
+ }
+ });
+ }
+ }
+ void getAllObjects(AtspiAccessiblePtr root, std::function<void(DBus::ValueOrError<std::vector<AtspiAccessiblePtr>>)> callback,
+ std::vector<int> roles = {}, std::vector<int> states = {})
+ {
+ auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+ auto col = atspi->getCollectionInterface(root);
+ if (!col) {
+ callback(DBus::Error{ "root '" + Atspi::getUniqueId(root) + "' doesn't have collection interface" });
+ } else {
+ atspi->getMatchedElements(col, ATSPI_Collection_SORT_ORDER_CANONICAL, 0,
+ Atspi::Matcher().states(states.begin(), states.end(), ATSPI_Collection_MATCH_ALL)
+ .roles(roles.begin(), roles.end(), ATSPI_Collection_MATCH_ANY)
+ , false, std::move(callback));
+ }
+ }
+ void makeUIElement(AtspiAccessiblePtr src, std::function<void(DBus::ValueOrError<std::shared_ptr<UIElement>>)> callback)
+ {
+ auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+ atspi->getComponentInterface(src, [src, callback = std::move(callback)](DBus::ValueOrError<AtspiComponentPtr> comp) {
+ if (!comp) {
+ callback(comp.getError());
+ return;
+ }
+ auto atspi = Singleton<UniversalSwitch>::instance().getAtspi();
+ atspi->getScreenPosition(std::get<0>(comp), [src, callback = std::move(callback)](DBus::ValueOrError<Rectangle> pos) {
+ if (!pos) {
+ callback(pos.getError());
+ return;
+ }
+ callback(std::make_shared<UIElement>(src, std::get<0>(pos).getCenterPoint(), UIElement::ApplicationCategory::OTHER));
+ });
+ });
+ }
+ struct PromiseObject {
+ std::promise<std::shared_ptr<UIElement>> promise;
+ bool set = false;
+
+ void setValue(std::shared_ptr<UIElement> v)
+ {
+ ASSERT(!set);
+ promise.set_value(std::move(v));
+ set = true;
+ }
+ template <typename T> void setException(T &&e)
+ {
+ ASSERT(!set);
+ promise.set_exception(std::make_exception_ptr(std::move(e)));
+ set = true;
+ }
+
+ ~PromiseObject()
+ {
+ if (!set) promise.set_value(nullptr);
+ }
+ };
+ std::shared_ptr<UIElement> convert(const std::string &requestedName) override
+ {
+ auto promiseObject = std::make_shared<PromiseObject>();
+ auto future = promiseObject->promise.get_future();
+
+ executeOnMainThread([promiseObject = std::move(promiseObject), this, &requestedName]() {
+ auto uiRoot = getVisibleRoot();
+ if (!uiRoot) {
+ promiseObject->setException(EvaluationFailure{} << "no visible root (context changed didn't happen)");
+ return;
+ }
+ auto root = uiRoot->getObject();
+ ASSERT(root);
+ getAllObjects(root, [promiseObject, &requestedName, this](DBus::ValueOrError<std::vector<AtspiAccessiblePtr>> elems) {
+ if (!promiseObject->set) {
+ if (!elems) {
+ promiseObject->setException(EvaluationFailure{} << elems.getError().message);
+ return;
+ }
+ findByName(std::get<0>(elems), requestedName,
+ [&requestedName, promiseObject, this](DBus::ValueOrError<std::vector<AtspiAccessiblePtr>> elements) {
+ if (!elements) {
+ promiseObject->setException(EvaluationFailure{} << elements.getError().message);
+ } else {
+ auto &e = std::get<0>(elements);
+ if (e.empty()) {
+ promiseObject->setException(EvaluationFailure{} << "no at-spi object found with name '" << requestedName << "'");
+ } else if (e.size() > 1) {
+ std::ostringstream names;
+ for (auto &elem : e) names << " " << Atspi::getUniqueId(elem);
+ promiseObject->setException(EvaluationFailure{} <<
+ "found more, than one at-spi object with name '" << requestedName << "' (see" << names.str() << ")");
+ } else {
+ makeUIElement(e[0], [promiseObject](DBus::ValueOrError<std::shared_ptr<UIElement>> elem) {
+ if (!elem)
+ promiseObject->setException(EvaluationFailure{} << elem.getError().message);
+ else
+ promiseObject->setValue(std::move(std::get<0>(elem)));
+ });
+ }
+ }
+ });
+ }
+ });
+ });
+ future.wait();
+ return std::move(future.get());
+ }
+
void insertStateConstants()
{
// from at-spi2-core v. 2.16.0