- Updated ATSPI codes to tell which window is visible or focused now.
- DevelWindow::VisibilityChangedSignal is used to check
whether the window is shown or not.
- Added Window::FocusChangeSignal to check whether the window is
activated.
1. Window show / hide -> object:state-chaged:showing
2. Window focus / unfocus -> WindowEvent::ACTIVATE
Change-Id: I38a6f8f67c303234857a57e8d812511942a95917
Signed-off-by: Seoyeon Kim <seoyeon2.kim@samsung.com>
namespace
{
-class NonControlAccessible : public virtual Accessible, public virtual Collection, public virtual Component
+class AdaptorAccessible : public virtual Accessible, public virtual Collection, public virtual Component
{
protected:
Dali::WeakHandle<Dali::Actor> mSelf;
{
auto handle = mSelf.GetHandle();
- // NonControlAccessible is deleted on ObjectDestroyedSignal
+ // AdaptorAccessible is deleted on ObjectDestroyedSignal
// for the respective actor (see `nonControlAccessibles`).
DALI_ASSERT_ALWAYS(handle);
}
public:
- NonControlAccessible(Dali::Actor actor, bool isRoot)
+ AdaptorAccessible(Dali::Actor actor, bool isRoot)
: mSelf(actor),
mRoot(isRoot)
{
{
return {};
}
-};
-using NonControlAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<NonControlAccessible> >;
+ Dali::Actor GetInternalActor() override
+ {
+ return mSelf.GetHandle();
+ }
+}; // AdaptorAccessible
-NonControlAccessiblesType nonControlAccessibles;
+using AdaptorAccessiblesType = std::unordered_map<const Dali::RefObject*, std::unique_ptr<AdaptorAccessible> >;
+
+// Save RefObject from an Actor in Accessible::Get()
+AdaptorAccessiblesType gAdaptorAccessibles;
std::function<Accessible*(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> Accessible* {
return nullptr;
objectRegistry = registry;
}
-void Accessible::RegisterControlAccessibilityGetter(std::function<Accessible*(Dali::Actor)> functor)
+void Accessible::RegisterExternalAccessibleGetter(std::function<Accessible*(Dali::Actor)> functor)
{
convertingFunctor = functor;
}
auto accessible = convertingFunctor(actor);
if(!accessible)
{
- if(nonControlAccessibles.empty() && objectRegistry)
+ if(gAdaptorAccessibles.empty() && objectRegistry)
{
objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) {
- nonControlAccessibles.erase(obj);
+ gAdaptorAccessibles.erase(obj);
});
}
- auto pair = nonControlAccessibles.emplace(&actor.GetBaseObject(), nullptr);
+ auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr);
if(pair.second)
{
- pair.first->second.reset(new NonControlAccessible(actor, isRoot));
+ pair.first->second.reset(new AdaptorAccessible(actor, isRoot));
}
accessible = pair.first->second.get();
}
+
return accessible;
}
//INTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/accessibility.h>
+#include <dali/public-api/adaptor-framework/window.h>
#include <dali/integration-api/debug.h>
namespace Dali
/**
* @brief Notifies accessibility dbus that window has just been shown.
+ *
+ * @param[in] window The window to be shown
*/
- virtual void WindowShown() = 0;
+ virtual void WindowShown(Window window) = 0;
/**
* @brief Notifies accessibility dbus that window has just been hidden.
+ *
+ * @param[in] window The window to be hidden
*/
- virtual void WindowHidden() = 0;
+ virtual void WindowHidden(Window window) = 0;
+
+ /**
+ * @brief Notifies accessibility dbus that window has just been focused.
+ *
+ * @param[in] window The window to be focused
+ */
+ virtual void WindowFocused(Window window) = 0;
+
+ /**
+ * @brief Notifies accessibility dbus that window has just been out of focus.
+ *
+ * @param[in] window The window to be out of focus
+ */
+ virtual void WindowUnfocused(Window window) = 0;
/**
* @brief Initializes accessibility bus.
virtual std::vector<Relation> GetRelationSet() = 0;
/**
+ * @brief Gets internal Actor to be saved before.
+ *
+ * @return The internal Actor
+ */
+ virtual Dali::Actor GetInternalActor() = 0;
+
+ /**
* @brief Gets all implemented interfaces.
*
* @return The collection of strings with implemented interfaces
return mIsOnRootLevel;
}
- /**
- * @brief The method registers functor resposible for converting Actor into Accessible.
- * @param functor The returning Accessible handle from Actor object
- */
- static void RegisterControlAccessibilityGetter(std::function<Accessible*(Dali::Actor)> functor);
-
- /**
- * @brief Acquires Accessible object from Actor object.
- *
- * @param[in] actor Actor object
- * @param[in] isRoot True, if it's top level object (window)
- *
- * @return The handle to Accessible object
- */
- static Accessible* Get(Dali::Actor actor, bool isRoot = false);
-
protected:
Accessible();
Accessible(const Accessible&) = delete;
*/
static void SetObjectRegistry(ObjectRegistry registry);
+ /**
+ * @brief The method registers functor resposible for converting Actor into Accessible.
+ * @param functor The returning Accessible handle from Actor object
+ */
+ static void RegisterExternalAccessibleGetter(std::function<Accessible*(Dali::Actor)> functor);
+
+ /**
+ * @brief Acquires Accessible object from Actor object.
+ *
+ * @param[in] actor Actor object
+ * @param[in] isRoot True, if it's top level object (window)
+ *
+ * @return The handle to Accessible object
+ */
+ static Accessible* Get(Dali::Actor actor, bool isRoot = false);
+
private:
friend class Bridge;
std::weak_ptr<Bridge::Data> mBridgeData;
bool mIsOnRootLevel = false;
-};
+
+}; // Accessible class
/**
* @brief Interface enabling to perform provided actions.
return {};
}
+ Dali::Actor GetInternalActor() override
+ {
+ return Dali::Actor{};
+ }
+
private:
Address mAddress;
};
#include <dali/internal/accessibility/bridge/bridge-base.h>
// EXTERNAL INCLUDES
+#include <dali/devel-api/common/stage.h>
#include <atomic>
#include <cstdlib>
#include <memory>
static Dali::Timer tickTimer;
-BridgeBase::~BridgeBase()
+BridgeBase::BridgeBase()
{
}
-BridgeBase::BridgeBase()
+BridgeBase::~BridgeBase()
{
+ mApplication.mChildren.clear();
+ mApplication.mWindows.clear();
}
void BridgeBase::AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor)
}
}
-void BridgeBase::AddTopLevelWindow(Accessible* root)
+void BridgeBase::OnWindowVisibilityChanged(Dali::Window window, bool visible)
+{
+ if(visible)
+ {
+ // TODO : Should we check 'out of screen' here? -> Then, we need an actor of this change.
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(window); // Called when Window is shown.
+ }
+ else
+ {
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(window); // Called when Window is hidden and iconified.
+ }
+
+}
+
+void BridgeBase::OnWindowFocusChanged(Dali::Window window, bool focusIn)
+{
+ if(focusIn)
+ {
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowFocused(window); // Called when Window is focused.
+ }
+ else
+ {
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowUnfocused(window); // Called when Window is out of focus.
+ }
+}
+
+void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
{
- mApplication.mChildren.push_back(root);
- SetIsOnRootLevel(root);
+ if(windowAccessible->GetInternalActor() == nullptr)
+ {
+ return;
+ }
+
+ // Prevent adding the default window twice.
+ if(!mApplication.mChildren.empty() &&
+ mApplication.mChildren[0]->GetInternalActor() == windowAccessible->GetInternalActor())
+ {
+ return;
+ }
+
+ // Adds Window to a list of Windows.
+ mApplication.mChildren.push_back(windowAccessible);
+ SetIsOnRootLevel(windowAccessible);
+
+ Dali::Window window = Dali::DevelWindow::Get(windowAccessible->GetInternalActor());
+ if(window)
+ {
+ mApplication.mWindows.push_back(window);
+ Dali::DevelWindow::VisibilityChangedSignal(window).Connect(this, &BridgeBase::OnWindowVisibilityChanged);
+ window.FocusChangeSignal().Connect(this, &BridgeBase::OnWindowFocusChanged);
+ }
}
-void BridgeBase::RemoveTopLevelWindow(Accessible* root)
+void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
{
+ for(auto i = 0u; i < mApplication.mWindows.size(); ++i)
+ {
+ if(windowAccessible->GetInternalActor() == mApplication.mWindows[i].GetRootLayer())
+ {
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(mApplication.mWindows[i]);
+ Dali::DevelWindow::VisibilityChangedSignal(mApplication.mWindows[i]).Disconnect(this, &BridgeBase::OnWindowVisibilityChanged);
+ mApplication.mWindows[i].FocusChangeSignal().Disconnect(this, &BridgeBase::OnWindowFocusChanged);
+ mApplication.mWindows.erase(mApplication.mWindows.begin() + i);
+ break;
+ }
+ }
+
for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
{
- if(mApplication.mChildren[i] == root)
+ if(mApplication.mChildren[i] == windowAccessible)
{
mApplication.mChildren.erase(mApplication.mChildren.begin() + i);
break;
// EXTERNAL INCLUDES
#include <dali/public-api/dali-adaptor-version.h>
#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/public-api/actors/layer.h>
#include <memory>
// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/internal/accessibility/bridge/accessibility-common.h>
/**
public:
Dali::Accessibility::EmptyAccessibleWithAddress mParent;
std::vector<Dali::Accessibility::Accessible*> mChildren;
+ std::vector<Dali::Window> mWindows;
std::string mName;
std::string GetName() override
}
/**
- * @brief Gets the active window.
+ * @brief Gets the Accessible object from the window.
*
- * @return Null if mChildren is empty, otherwise the active window
+ * @param[in] window The window to find
+ * @return Null if mChildren is empty, otherwise the Accessible object
* @note Currently, the default window would be returned when mChildren is not empty.
*/
- Dali::Accessibility::Accessible* GetActiveWindow()
+ Dali::Accessibility::Accessible* GetWindowAccessible(Dali::Window window)
{
- return mChildren.empty() ? nullptr : mChildren[0];
+ if(mChildren.empty())
+ {
+ return nullptr;
+ }
+
+ Dali::Layer rootLayer = window.GetRootLayer();
+
+ // Find a child which is related to the window.
+ for(auto i = 0u; i < mChildren.size(); ++i)
+ {
+ if(rootLayer == mChildren[i]->GetInternalActor())
+ {
+ return mChildren[i];
+ }
+ }
+
+ // If can't find its children, return the default window.
+ return mChildren[0];
}
bool DoGesture(const Dali::Accessibility::GestureInfo& gestureInfo) override
return {};
}
+ Dali::Actor GetInternalActor() override
+ {
+ return Dali::Actor{};
+ }
+
Dali::Accessibility::Address GetAddress() override
{
return {"", "root"};
void AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
/**
+ * @brief Callback when the visibility of the window is changed.
+ *
+ * @param[in] window The window to be changed
+ * @param[in] visible The visibility of the window
+ */
+ void OnWindowVisibilityChanged(Dali::Window window, bool visible);
+
+ /**
+ * @brief Callback when the window focus is changed.
+ *
+ * @param[in] window The window whose focus is changed
+ * @param[in] focusIn Whether the focus is in/out
+ */
+ void OnWindowFocusChanged(Dali::Window window, bool focusIn);
+
+ /**
* @copydoc Dali::Accessibility::Bridge::GetBusName()
*/
const std::string& GetBusName() const override;
/**
* @copydoc Dali::Accessibility::Bridge::AddTopLevelWindow()
*/
- void AddTopLevelWindow(Dali::Accessibility::Accessible* window) override;
+ void AddTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
/**
* @copydoc Dali::Accessibility::Bridge::RemoveTopLevelWindow()
*/
- void RemoveTopLevelWindow(Dali::Accessibility::Accessible* window) override;
+ void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
/**
* @copydoc Dali::Accessibility::Bridge::AddPopup()
mRegistryClient = {};
mDirectReadingClient = {};
mDirectReadingCallbacks.clear();
+ mApplication.mChildren.clear();
+ mApplication.mWindows.clear();
}
/**
assert(res);
mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
+
if(mIsShown)
{
- EmitActivate();
+ auto rootLayer = Dali::Stage::GetCurrent().GetRootLayer();
+ auto window = Dali::DevelWindow::Get(rootLayer);
+ EmitActivate(window); // Currently, sends a signal that the default window is activated here.
}
return ForceUpResult::JUST_STARTED;
}
/**
- * @brief Sends a signal to dbus that the default window is activated.
+ * @brief Sends a signal to dbus that the window is shown.
+ *
+ * @param[in] window The window to be shown
+ * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
+ */
+ void EmitShown(Dali::Window window)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
+ {
+ windowAccessible->EmitShowing(true);
+ }
+ }
+
+ /**
+ * @brief Sends a signal to dbus that the window is hidden.
+ *
+ * @param[in] window The window to be hidden
+ * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
+ */
+ void EmitHidden(Dali::Window window)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
+ {
+ windowAccessible->EmitShowing(false);
+ }
+ }
+
+ /**
+ * @brief Sends a signal to dbus that the window is activated.
*
- * TODO : This is subject to change if/when we implement multi-window support.
+ * @param[in] window The window to be activated
* @see BridgeObject::Emit()
*/
- void EmitActivate()
+ void EmitActivate(Dali::Window window)
{
- auto win = mApplication.GetActiveWindow();
- if(win)
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
{
- win->Emit(WindowEvent::ACTIVATE, 0);
+ windowAccessible->Emit(WindowEvent::ACTIVATE, 0);
}
}
/**
- * @brief Sends a signal to dbus that the default window is deactivated.
+ * @brief Sends a signal to dbus that the window is deactivated.
*
- * TODO : This is subject to change if/when we implement multi-window support.
+ * @param[in] window The window to be deactivated
* @see BridgeObject::Emit()
*/
- void EmitDeactivate()
+ void EmitDeactivate(Dali::Window window)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
+ {
+ windowAccessible->Emit(WindowEvent::DEACTIVATE, 0);
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowShown()
+ */
+ void WindowShown(Dali::Window window) override
{
- auto win = mApplication.GetActiveWindow();
- if(win)
+ if(!mIsShown && IsUp())
{
- win->Emit(WindowEvent::DEACTIVATE, 0);
+ EmitShown(window);
}
+ mIsShown = true;
}
/**
* @copydoc Dali::Accessibility::Bridge::WindowHidden()
*/
- void WindowHidden() override
+ void WindowHidden(Dali::Window window) override
{
if(mIsShown && IsUp())
{
- EmitDeactivate();
+ EmitHidden(window);
}
mIsShown = false;
}
/**
- * @copydoc Dali::Accessibility::Bridge::WindowShown()
+ * @copydoc Dali::Accessibility::Bridge::WindowFocused()
*/
- void WindowShown() override
+ void WindowFocused(Dali::Window window) override
{
- if(!mIsShown && IsUp())
+ if(mIsShown && IsUp())
{
- EmitActivate();
+ EmitActivate(window);
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowUnfocused()
+ */
+ void WindowUnfocused(Dali::Window window) override
+ {
+ if(mIsShown && IsUp())
+ {
+ EmitDeactivate(window);
}
- mIsShown = true;
}
void ReadAndListenProperty()
return;
}
- auto rootLayer = Dali::Stage::GetCurrent().GetRootLayer();
+ auto rootLayer = Dali::Stage::GetCurrent().GetRootLayer(); // A root layer of the default window.
auto window = Dali::DevelWindow::Get(rootLayer);
auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
+ auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+
auto* bridge = Bridge::GetCurrentBridge();
- bridge->AddTopLevelWindow(Dali::Accessibility::Accessible::Get(rootLayer, true));
+ bridge->AddTopLevelWindow(accessible);
bridge->SetApplicationName(applicationName);
bridge->Initialize();
if(window && window.IsVisible())
{
- bridge->WindowShown();
+ bridge->WindowShown(window);
}
}
return nullptr;
}
- void WindowShown() override
+ void WindowShown(Window window) override
{
}
- void WindowHidden() override
+ void WindowHidden(Window window) override
+ {
+ }
+
+ void WindowFocused(Window window) override
+ {
+ }
+
+ void WindowUnfocused(Window window) override
{
}
Adaptor::~Adaptor()
{
- Accessibility::Bridge::GetCurrentBridge()->WindowHidden();
Accessibility::Bridge::GetCurrentBridge()->Terminate();
// Ensure stop status
void Adaptor::OnWindowShown()
{
- Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown();
-
if(PAUSED_WHILE_HIDDEN == mState)
{
// Adaptor can now be resumed
void Adaptor::OnWindowHidden()
{
- Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden();
-
if(RUNNING == mState || READY == mState)
{
bool allWindowsHidden = true;
void Application::QuitFromMainLoop()
{
- Accessibility::Bridge::GetCurrentBridge()->WindowHidden();
Accessibility::Bridge::GetCurrentBridge()->Terminate();
mAdaptor->Stop();
Window::~Window()
{
+ auto bridge = Accessibility::Bridge::GetCurrentBridge();
+ auto rootLayer = mScene.GetRootLayer();
+ auto accessible = Accessibility::Accessible::Get(rootLayer);
+ bridge->RemoveTopLevelWindow(accessible);
+
if(mAdaptor)
{
- auto bridge = Accessibility::Bridge::GetCurrentBridge();
- auto rootLayer = mScene.GetRootLayer();
- auto accessible = Accessibility::Accessible::Get(rootLayer);
- bridge->RemoveTopLevelWindow(accessible);
-
mAdaptor->RemoveWindow(this);
}
mEventHandler = EventHandlerPtr(new EventHandler(mWindowSurface->GetWindowBase(), *mAdaptor));
mEventHandler->AddObserver(*this);
+ // Add Window to bridge for ATSPI
auto bridge = Accessibility::Bridge::GetCurrentBridge();
auto rootLayer = mScene.GetRootLayer();
auto accessible = Accessibility::Accessible::Get(rootLayer, true);
{
if(focusIn)
{
- bridge->WindowShown();
+ bridge->WindowFocused(handle);
}
else
{
- bridge->WindowHidden();
+ bridge->WindowUnfocused(handle);
}
}
}