An atspi object can be removed even if ref count isn't zero, when a parent window is destroyed.
on object destroyed callback, uiobject set invalid flag by itself
to prevent crahsing by calling atspi api with invalid handler.
Change-Id: Ifb8efee7b97d46e418404aea30198a72ebe90fcd
#include <memory>
#include <string>
#include <vector>
+#include <mutex>
#include "AccessibleUtils.h"
+#include "IEventConsumer.h"
+
#include "Rect.h"
#include "config.h"
* @brief AccessibleNode Class
* @since_tizen 5.5
*/
-class AccessibleNode {
+class AccessibleNode : public std::enable_shared_from_this<AccessibleNode>, public IEventConsumer {
public: // Constructor & Destructor
/**
* @brief TBD
*/
virtual std::shared_ptr<AccessibleNode> getParent() const = 0;
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ void notify(int type, int type2, void *src) override;
+
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ void invalidate();
+
public:
/**
* @brief TBD
*/
virtual void setValue(std::string text) = 0;
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ virtual bool isValid() const;
+
public:
/**
* @brief TBD
* @brief TBD
*/
int mFeatureProperty;
+
+private:
+ /**
+ * @brief TBD
+ */
+ bool mValid;
+
+ /**
+ * @brief TBD
+ */
+ mutable std::mutex mLock;
};
\ No newline at end of file
#include "AccessibleApplication.h"
#include "AccessibleWindow.h"
#include "AccessibleNode.h"
-
#include "AccessibleUtils.h"
+#include "IEventSource.h"
#include <memory>
#include <vector>
-
+#include <set>
+#include <mutex>
#include "config.h"
-
/**
* @brief AccessibleWatcher class
* @since_tizen 5.5
*/
-class AccessibleWatcher {
+class AccessibleWatcher : public IEventSource {
public:
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ AccessibleWatcher();
+
/**
* @brief TBD
* @since_tizen 5.5
* @brief TBD
* @since_tizen 5.5
*/
- static const AccessibleWatcher *getInstance(AccessibleWatcher *watcherImpl = nullptr);
+ static AccessibleWatcher *getInstance(AccessibleWatcher *watcherImpl = nullptr);
public:
/**
* @since_tizen 5.5
*/
virtual std::vector<std::shared_ptr<AccessibleApplication>> getActiveApplications(void) const;
+public:
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ void attach(std::shared_ptr<IEventConsumer> source) override;
+
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ void detach(std::shared_ptr<IEventConsumer> source) override;
+
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ void notifyAll(int type, int type2, void *src) override;
+
+private:
+ /**
+ * @brief TBD
+ */
+ std::set<std::shared_ptr<IEventConsumer>> mSources;
+
+ /**
+ * @brief TBD
+ */
+ std::mutex mLock;
};
\ No newline at end of file
* @brief TBD
* @since_tizen 5.5
*/
- bool isValid() const;
+ bool isValid() const override;
public:
/**
#include <atspi/atspi.h>
#include <gio/gio.h>
-#include <mutex>
#include <shared_mutex>
#include <memory>
#include <list>
* @brief TBD
* @since_tizen 5.5
*/
- static void onAtspiWindowEvent(AtspiEvent *event, void *user_data);
+ static void onAtspiEvents(AtspiEvent *event, void *user_data);
/**
* @brief TBD
*/
GDBusProxy * mDbusProxy;
- /**
- * @brief TBD
- */
- std::mutex mLock;
-
/**
* @brief TBD
*/
#include <mutex>
#include <set>
-class MockAccessibleNode : public AccessibleNode, public std::enable_shared_from_this<MockAccessibleNode> {
+class MockAccessibleNode : public AccessibleNode {
public:
/**
* @brief TBD
* @since_tizen 5.5
*/
- MockAccessibleNode(std::shared_ptr<MockAccessibleNode> parent, std::string text,std::string pkg,std::string role, std::string id, std::string type,std::string style, std::string automationId, Rect<int> boundingBox,int supportingIfaces,int featureProperty);
+ MockAccessibleNode(std::shared_ptr<AccessibleNode> parent, std::string text,std::string pkg,std::string role, std::string id, std::string type,std::string style, std::string automationId, Rect<int> boundingBox,int supportingIfaces,int featureProperty);
/**
* @brief TBD
* @brief TBD
*/
std::vector<std::shared_ptr<AccessibleApplication>> mApplicationList;
-
- /**
- * @brief TBD
- */
- std::mutex mLock;
};
\ No newline at end of file
*/
void refresh() const;
+ /**
+ * @brief TBD
+ * @since_tizen 5.5
+ */
+ bool isValid() const;
+
/**
* @brief TBD
* @since_tizen 5.5
}
AccessibleNode::AccessibleNode()
- : mText{""}, mPkg{""}, mRole{""}, mId{""}, mAutomationId{""}, mType{""}, mStyle{""},
- mBoundingBox{0,0,0,0}, mSupportingIfaces(0), mFeatureProperty(0)
+: mText{""}, mPkg{""}, mRole{""}, mId{""}, mType{""}, mStyle{""},
+ mBoundingBox{0,0,0,0}, mSupportingIfaces(0), mFeatureProperty(0), mValid{true}, mLock{}
{
}
return ss.str();
}
+void AccessibleNode::notify(int type, int type2, void *src)
+{
+ LOG_SCOPE_F(INFO, "notified for obj(%p) t1:%d t2:%d src:%p",this, type, type2, src);
+ void *handler = getRawHandler();
+
+ if ((EventType)type == EventType::Object && (ObjectEventType)type2 == ObjectEventType::ObjectStateDefunct) {
+ if (handler == src) invalidate();
+ }
+}
+
+void AccessibleNode::invalidate()
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ LOG_F(INFO, "object %p is now invalid", this);
+ mValid = false;
+}
+
+bool AccessibleNode::isValid() const
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ if (!getRawHandler() || !mValid) return false;
+ return true;
+}
+
void AccessibleNode::print(int depth, int maxDepth)
{
if (maxDepth <= 0 || depth > maxDepth) return;
#include <algorithm>
#include <loguru.hpp>
-
+AccessibleWatcher::AccessibleWatcher()
+:mSources{}, mLock{}
+{
+}
AccessibleWatcher::~AccessibleWatcher()
{
}
*/
-const AccessibleWatcher *AccessibleWatcher::getInstance(AccessibleWatcher *watcherImpl)
+AccessibleWatcher *AccessibleWatcher::getInstance(AccessibleWatcher *watcherImpl)
{
static AccessibleWatcher *mInstance = nullptr;
if (watcherImpl) {
LOG_F(INFO, "active apps size %d", apps.size());
return apps;
-}
\ No newline at end of file
+}
+
+void AccessibleWatcher::attach(std::shared_ptr<IEventConsumer> source)
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ LOG_F(INFO, "source attached %p", source.get());
+ if (source) {
+ mSources.insert(source);
+ }
+}
+
+void AccessibleWatcher::detach(std::shared_ptr<IEventConsumer> source)
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ LOG_F(INFO, "source detached %p", source.get());
+ if (source) {
+ auto iter = mSources.find(source);
+ if (iter != mSources.end()) mSources.erase(iter);
+ }
+}
+
+void AccessibleWatcher::notifyAll(int type, int type2, void *src)
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ std::for_each(mSources.begin(), mSources.end(), [&](auto source){
+ source->notify(type, type2, src);
+ });
+}
#include "AtspiAccessibleNode.h"
+#include "AccessibleWatcher.h"
#include <gio/gio.h>
AtspiAccessibleNode::AtspiAccessibleNode(AtspiAccessible *node)
: mNode{node}
{
- if (mNode) {
- GArray *ifaces = atspi_accessible_get_interfaces(mNode);
+ const auto trickDontRemove = std::shared_ptr<AtspiAccessibleNode>( this, [](AtspiAccessibleNode*){} );
+ auto watcher = AccessibleWatcher::getInstance();
+ watcher->attach(shared_from_this());
+
+ if (mNode) {
+ GArray *ifaces = atspi_accessible_get_interfaces(mNode);
if (ifaces) {
for (unsigned int i = 0; i < ifaces->len; i++) {
char *iface = g_array_index(ifaces, char *, i);
AtspiAccessibleNode::~AtspiAccessibleNode()
{
+ auto watcher = AccessibleWatcher::getInstance();
+ watcher->detach(shared_from_this());
if(mNode) g_object_unref(mNode);
}
std::shared_ptr<AccessibleNode> AtspiAccessibleNode::getChildAt(int index) const
{
- if (!isValid()) std::make_shared<AtspiAccessibleNode>(nullptr);
+ if (!isValid()) return std::make_shared<AtspiAccessibleNode>(nullptr);
LOG_SCOPE_F(INFO, "getChild @ %d from node(%p)", index, mNode);
AtspiAccessible *rawChild = atspi_accessible_get_child_at_index(mNode, index, NULL);
return std::make_shared<AtspiAccessibleNode>(rawChild);
}
bool AtspiAccessibleNode::isValid() const
{
- if (!mNode) return false;
+ if(!AccessibleNode::isValid()) return false;
AtspiStateSet *st = atspi_accessible_get_state_set(mNode);
if (!st) return false;
}
AtspiAccessibleWatcher::AtspiAccessibleWatcher()
-: mDbusProxy{nullptr}, mLock{}
+: mDbusProxy{nullptr}
{
GVariant *enabled_variant = nullptr, *result = nullptr;
GError * error = nullptr;
atspi_init();
listener =
- atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiWindowEvent, this, NULL);
+ atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiEvents, this, NULL);
- atspi_event_listener_register(listener, "window:create", NULL);
- atspi_event_listener_register(listener, "window:destroy", NULL);
- atspi_event_listener_register(listener, "window:activate", NULL);
- atspi_event_listener_register(listener, "window:deactivate", NULL);
+ atspi_event_listener_register(listener, "window:", NULL);
atspi_event_listener_register(listener, "object:", NULL);
mDbusProxy = g_dbus_proxy_new_for_bus_sync(
}
-void AtspiAccessibleWatcher::onAtspiWindowEvent(AtspiEvent *event, void *user_data)
+void AtspiAccessibleWatcher::onAtspiEvents(AtspiEvent *event, void *user_data)
{
char *name = NULL, *pname = NULL;
AtspiAccessibleWatcher *instance = (AtspiAccessibleWatcher *)user_data;
return;
}
-
- AtspiAccessible *parent = atspi_accessible_get_parent(event->source, NULL);
-
name = atspi_accessible_get_name(event->source, NULL);
+ AtspiAccessible *parent = atspi_accessible_get_parent(event->source, NULL);
if (parent) {
pname = atspi_accessible_get_name(parent, NULL);
g_object_unref(parent);
}
- LOG_SCOPE_F(INFO, "event:%s, src:%p(%s), p:%p(%s), d1:%p d2:%p instance:%p",
- event->type, event->source, name, parent, pname, event->detail1,
- event->detail2, instance);
-
if (!strcmp(event->type, "window:activate")) {
instance->onWindowActivated(
static_cast<AtspiAccessible *>(event->source),
void AtspiAccessibleWatcher::onWindowActivated(AtspiAccessible *node,
WindowActivateInfoType type)
{
- //std::unique_lock<std::mutex> lock(mLock);
LOG_SCOPE_F(INFO, "onWindowActivated obj:%p", node);
- //addToActivatedList((node));
- return;
+ notifyAll((int)EventType::Window, (int)WindowEventType::WindowActivated, node);
}
void AtspiAccessibleWatcher::onWindowDeactivated(AtspiAccessible *node)
{
- std::unique_lock<std::mutex> lock(mLock);
LOG_SCOPE_F(INFO, "onWindowDeactivated obj:%p", node);
- //removeFromActivatedList(node);
+ notifyAll((int)EventType::Window, (int)WindowEventType::WindowDeactivated, node);
}
void AtspiAccessibleWatcher::onWindowCreated(AtspiAccessible *node)
{
- std::unique_lock<std::mutex> lock(mLock);
LOG_SCOPE_F(INFO, "onWindowCreated obj:%p", node);
- //addToWindowSet(node);
+ notifyAll((int)EventType::Window, (int)WindowEventType::WindowCreated, node);
}
void AtspiAccessibleWatcher::onWindowDestroyed(AtspiAccessible *node)
{
- std::unique_lock<std::mutex> lock(mLock);
LOG_SCOPE_F(INFO, "onWindowDestroyed obj:%p vis:%d", node);
- //removeFromWindowSet(node);
+ notifyAll((int)EventType::Window, (int)WindowEventType::WindowDestroyed, node);
}
void AtspiAccessibleWatcher::onVisibilityChanged(AtspiAccessible *node, bool visible)
{
- std::unique_lock<std::mutex> lock(mLock);
- LOG_SCOPE_F(INFO, "onVisibilityChanged obj:%p vis:%d", node, visible);
+ LOG_SCOPE_F(INFO, "onVisibilityChanged obj:%p", node);
+ notifyAll((int)EventType::Object, (int)ObjectEventType::ObjectStateVisible, node);
}
void AtspiAccessibleWatcher::onObjectDefunct(AtspiAccessible *node)
{
- std::unique_lock<std::mutex> lock(mLock);
LOG_SCOPE_F(INFO, "onObjectDefunct obj:%p", node);
+ notifyAll((int)EventType::Object, (int)ObjectEventType::ObjectStateDefunct, node);
}
}
return false;
}
-
-/*
-std::shared_ptr<AccessibleNode> AtspiAccessibleWatcher::getRootNode() const
-{
- auto node = atspi_get_desktop(0);
- auto aNode = std::make_shared<AccessibleNode>(node);
- return accNode;
-}
-
-std::vector<std::shared_ptr<AccessibleNode>> AtspiAccessibleWatcher::getTopNode() const
-{
- AtspiAccessible *topNode = nullptr, *activeNode = nullptr;
- std::vector<std::shared_ptr<AccessibleNode>> ret;
-
- {
- std::unique_lock<std::mutex> lock(mLock);
- if (!mActivatedWindowList.empty()) {
- topNode = mActivatedWindowList.front();
- std::list<AtspiAccessible *>::const_iterator iterator;
- for (iterator = mActivatedWindowList.begin(); iterator != mActivatedWindowList.end(); ++iterator){
- if (*iterator && iShowingNode(*iterator)) {
- AtspiAccessible *child = atspi_accessible_get_application(*iterator, NULL);
- if (child) {
- auto tmpNode = make_gobj_unique(child);
- auto node = AccessibleNode::get(tmpNode.get());
- if (tmpNode.get()) g_object_unref(tmpNode.get());
- ret.push_back((node));
- }
- }
- }
- return ret;
- }
- }
-
- LOG_F(INFO, "Mo activated window node or Invisible acticated window / topNdoe(%p)", topNode);
- LOG_F(INFO, "Trying fallback logic");
-
- auto rootNode = make_gobj_unique(atspi_get_desktop(0));
-
- if (rootNode) {
- std::vector<AtspiAccessible*> activeNodes = findActiveNode(rootNode.get(), 0, 2);
- if (!activeNodes.empty()) {
- std::set<AtspiAccessible*> appset{};
- for (auto iterator = activeNodes.begin(); iterator != activeNodes.end(); ++iterator){
- //auto tmpNode = make_gobj_unique(atspi_accessible_get_application(*iterator, NULL));
- auto app = atspi_accessible_get_application(*iterator, NULL);
- appset.insert(app);
- }
- for (auto iterator = appset.begin(); iterator != appset.end(); ++iterator){
- auto node = AccessibleNode::get(*iterator);
- g_object_unref(*iterator);
- LOG_F(INFO, "app has showing window found %p %s %s", node.get(), node->getText().c_str(), node->getPkg().c_str());
- ret.push_back((node));
- }
- } else {
- auto node = AccessibleNode::get(rootNode.get());
- if (rootNode.get()) g_object_unref(rootNode.get());
- ret.push_back((node));
- }
- }
- return ret;
-}
-*/
-/*
-void AtspiAccessibleWatcher::clearWindowList()
-{
- std::unique_lock<std::mutex> lock(mLock);
-
- std::for_each(mActivatedWindowSet.begin(), mActivatedWindowSet.end(), [](auto window){
- g_object_unref(window);
- });
- mActivatedWindowSet.clear();
-
- mWindowSet.clear();
-}
-*/
\ No newline at end of file
#include "MockAccessibleNode.h"
+#include "AccessibleWatcher.h"
#include <algorithm>
#include <iostream>
-MockAccessibleNode::MockAccessibleNode(std::shared_ptr<MockAccessibleNode> parent, std::string text, std::string pkg, std::string role, std::string res, std::string type, std::string style,std::string automationId, Rect<int> boundingBox, int supportingIfaces,int featureProperty)
-: mParentNode(parent), mChildrenList{}, mActionSet{}, mLock{}
+MockAccessibleNode::MockAccessibleNode(std::shared_ptr<AccessibleNode> parent, std::string text, std::string pkg, std::string role, std::string res, std::string type, std::string style,std::string automationId, Rect<int> boundingBox, int supportingIfaces,int featureProperty)
+: mParentNode(parent), mChildrenList{}, mActionSet{}
{
+ printf("%s:%d / %s\n",__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ const auto trickDontRemove = std::shared_ptr<MockAccessibleNode>( this, [](MockAccessibleNode*){} );
+
setProperties(text,pkg,role,res,type,style,automationId, boundingBox, supportingIfaces, featureProperty);
+ auto watcher = AccessibleWatcher::getInstance();
+ watcher->attach(shared_from_this());
}
MockAccessibleNode::~MockAccessibleNode()
{
+ printf("%s:%d / %s\n",__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ auto watcher = AccessibleWatcher::getInstance();
+ watcher->detach(shared_from_this());
}
int MockAccessibleNode::getChildCount() const
void* MockAccessibleNode::getRawHandler(void) const
{
- return (void*)0;
+ printf("%s:%d / %s\n",__FILE__, __LINE__, __PRETTY_FUNCTION__);
+ return (void*)1;
}
void MockAccessibleNode::setProperties(std::string text,std::string pkg,std::string role,std::string id,std::string type,std::string style,std::string automationId, Rect<int> boundingBox,int supportingIfaces,int featureProperty)
std::shared_ptr<MockAccessibleNode> MockAccessibleNode::addChild(std::string text, std::string pkg, std::string role, std::string res, std::string type, std::string style, std::string automationId, Rect<int> geometry, int ifaces, int properties)
{
- std::unique_lock<std::mutex> lock(mLock);
-
auto node = std::make_shared<MockAccessibleNode>(shared_from_this(), text, pkg, role, res, type, style, automationId, geometry, ifaces, properties);
this->addChild(node);
return node;
bool TizenDeviceImpl::click(const int x, const int y, const unsigned int intv)
{
+ LOG_SCOPE_F(INFO, "click %d %d , intv:%d", x, y, intv);
+
int seq = touchDown(x, y);
if (seq < 0) return false;
usleep(intv * MSEC_PER_SEC);
int TizenDeviceImpl::touchDown(const int x, const int y)
{
int seq = grabTouchSeqNumber();
- LOG_F(INFO, "touch down %d %d , seq:%d", x, y, seq);
+ LOG_SCOPE_F(INFO, "touch down %d %d , seq:%d", x, y, seq);
if (seq >= 0) {
auto args = std::make_tuple(this, x, y, seq);
long result = (long)ecore_main_loop_thread_safe_call_sync([](void *data)->void*{
bool TizenDeviceImpl::touchMove(const int x, const int y, const int seq)
{
- LOG_F(INFO, "touch move %d %d, seq:%d", x, y, seq);
+ LOG_SCOPE_F(INFO, "touch move %d %d, seq:%d", x, y, seq);
if (seq >= 0) {
auto args = std::make_tuple(this, x, y, seq);
long result = (long)ecore_main_loop_thread_safe_call_sync([](void *data)->void*{
bool TizenDeviceImpl::touchUp(const int x, const int y, const int seq)
{
- LOG_F(INFO, "touch up %d %d, seq:%d", x, y, seq);
+ LOG_SCOPE_F(INFO, "touch up %d %d, seq:%d", x, y, seq);
if (seq >= 0) {
auto args = std::make_tuple(this, x, y, seq);
long result = (long)ecore_main_loop_thread_safe_call_sync([](void *data)->void*{
bool TizenDeviceImpl::wheelUp(int amount, const int durationMs)
{
- LOG_F(INFO, "wheel up %d for %d", amount, durationMs);
+ LOG_SCOPE_F(INFO, "wheel up %d for %d", amount, durationMs);
auto args = std::make_tuple(this);
long result = -1;
for (int i = 0; i < amount; i++){
bool TizenDeviceImpl::wheelDown(int amount, const int durationMs)
{
- LOG_F(INFO, "wheel down %d for %d", amount, durationMs);
+ LOG_SCOPE_F(INFO, "wheel down %d for %d", amount, durationMs);
auto args = std::make_tuple(this);
long result = -1;
for (int i = 0; i < amount; i++){
mNode->refresh();
}
+bool UiObject::isValid() const
+{
+ return mNode->isValid();
+}
+
const Rect<int> UiObject::getBoundingBox() const
{
mNode->refresh();