2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/accessibility/bridge/bridge-base.h>
22 #include <dali/devel-api/common/stage.h>
28 #include <dali/public-api/adaptor-framework/timer.h>
30 using namespace Dali::Accessibility;
32 static Dali::Timer tickTimer;
34 BridgeBase::BridgeBase()
38 BridgeBase::~BridgeBase()
40 mApplication.mChildren.clear();
41 mApplication.mWindows.clear();
44 void BridgeBase::AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor)
51 auto it = mFilteredEvents.insert({{kind, obj}, {static_cast<unsigned int>(delay * 10), {}}});
58 it.first->second.second = std::move(functor);
63 tickTimer = Dali::Timer::New(100);
64 tickTimer.TickSignal().Connect(this, &BridgeBase::TickFilteredEvents);
68 bool BridgeBase::TickFilteredEvents()
70 for(auto it = mFilteredEvents.begin(); it != mFilteredEvents.end();)
81 it->second.second = {};
85 it = mFilteredEvents.erase(it);
91 return !mFilteredEvents.empty();
94 void BridgeBase::UpdateRegisteredEvents()
96 using ReturnType = std::vector<std::tuple<std::string, std::string>>;
97 mRegistry.method<DBus::ValueOrError<ReturnType>()>("GetRegisteredEvents").asyncCall([this](DBus::ValueOrError<ReturnType> msg) {
100 LOG() << "Get registered events failed";
104 IsBoundsChangedEventAllowed = false;
106 ReturnType values = std::get<ReturnType>(msg.getValues());
107 for(long unsigned int i = 0; i < values.size(); i++)
109 if(!std::get<1>(values[i]).compare("Object:BoundsChanged"))
111 IsBoundsChangedEventAllowed = true;
117 BridgeBase::ForceUpResult BridgeBase::ForceUp()
119 if(Bridge::ForceUp() == ForceUpResult::ALREADY_UP)
121 return ForceUpResult::ALREADY_UP;
123 auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
124 auto addr = proxy.method<std::string()>(dbusLocators::atspi::GET_ADDRESS).call();
128 throw std::domain_error{std::string("failed at call '") + dbusLocators::atspi::GET_ADDRESS + "': " + addr.getError().message};
131 mConnectionPtr = DBusWrapper::Installed()->eldbus_address_connection_get_impl(std::get<0>(addr));
132 mData->mBusName = DBus::getConnectionName(mConnectionPtr);
133 mDbusServer = {mConnectionPtr};
136 DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCache};
137 AddFunctionToInterface(desc, "GetItems", &BridgeBase::GetItems);
138 mDbusServer.addInterface(AtspiDbusPathCache, desc);
141 DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceApplication};
142 AddGetSetPropertyToInterface(desc, "Id", &BridgeBase::GetId, &BridgeBase::SetId);
143 mDbusServer.addInterface(AtspiPath, desc);
146 mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, AtspiDbusInterfaceRegistry, mConnectionPtr};
148 UpdateRegisteredEvents();
150 mRegistry.addSignal<void(void)>("EventListenerRegistered", [this](void) {
151 UpdateRegisteredEvents();
154 mRegistry.addSignal<void(void)>("EventListenerDeregistered", [this](void) {
155 UpdateRegisteredEvents();
158 return ForceUpResult::JUST_STARTED;
161 void BridgeBase::ForceDown()
169 const std::string& BridgeBase::GetBusName() const
171 static std::string empty;
172 return mData ? mData->mBusName : empty;
175 Accessible* BridgeBase::FindByPath(const std::string& name) const
181 catch(std::domain_error&)
187 void BridgeBase::AddPopup(Accessible* object)
189 if(std::find(mPopups.begin(), mPopups.end(), object) != mPopups.end())
193 mPopups.push_back(object);
196 object->Emit(WindowEvent::ACTIVATE, 0);
200 void BridgeBase::RemovePopup(Accessible* object)
202 auto it = std::find(mPopups.begin(), mPopups.end(), object);
203 if(it == mPopups.end())
211 object->Emit(WindowEvent::DEACTIVATE, 0);
214 mApplication.mChildren.back()->Emit(WindowEvent::ACTIVATE, 0);
218 mPopups.back()->Emit(WindowEvent::ACTIVATE, 0);
223 void BridgeBase::OnWindowVisibilityChanged(Dali::Window window, bool visible)
227 // TODO : Should we check 'out of screen' here? -> Then, we need an actor of this change.
228 Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(window); // Called when Window is shown.
232 Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(window); // Called when Window is hidden and iconified.
237 void BridgeBase::OnWindowFocusChanged(Dali::Window window, bool focusIn)
241 Dali::Accessibility::Bridge::GetCurrentBridge()->WindowFocused(window); // Called when Window is focused.
245 Dali::Accessibility::Bridge::GetCurrentBridge()->WindowUnfocused(window); // Called when Window is out of focus.
249 void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
251 if(windowAccessible->GetInternalActor() == nullptr)
256 // Prevent adding the default window twice.
257 if(!mApplication.mChildren.empty() &&
258 mApplication.mChildren[0]->GetInternalActor() == windowAccessible->GetInternalActor())
263 // Adds Window to a list of Windows.
264 mApplication.mChildren.push_back(windowAccessible);
265 SetIsOnRootLevel(windowAccessible);
267 Dali::Window window = Dali::DevelWindow::Get(windowAccessible->GetInternalActor());
270 mApplication.mWindows.push_back(window);
271 Dali::DevelWindow::VisibilityChangedSignal(window).Connect(this, &BridgeBase::OnWindowVisibilityChanged);
272 window.FocusChangeSignal().Connect(this, &BridgeBase::OnWindowFocusChanged);
276 void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
278 for(auto i = 0u; i < mApplication.mWindows.size(); ++i)
280 if(windowAccessible->GetInternalActor() == mApplication.mWindows[i].GetRootLayer())
282 Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(mApplication.mWindows[i]);
283 Dali::DevelWindow::VisibilityChangedSignal(mApplication.mWindows[i]).Disconnect(this, &BridgeBase::OnWindowVisibilityChanged);
284 mApplication.mWindows[i].FocusChangeSignal().Disconnect(this, &BridgeBase::OnWindowFocusChanged);
285 mApplication.mWindows.erase(mApplication.mWindows.begin() + i);
290 for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
292 if(mApplication.mChildren[i] == windowAccessible)
294 mApplication.mChildren.erase(mApplication.mChildren.begin() + i);
300 std::string BridgeBase::StripPrefix(const std::string& path)
302 auto size = strlen(AtspiPath);
303 return path.substr(size + 1);
306 Accessible* BridgeBase::Find(const std::string& path) const
310 return &mApplication;
314 std::istringstream tmp{path};
315 if(!(tmp >> accessible))
317 throw std::domain_error{"invalid path '" + path + "'"};
320 auto it = mData->mKnownObjects.find(static_cast<Accessible*>(accessible));
321 if(it == mData->mKnownObjects.end())
323 throw std::domain_error{"unknown object '" + path + "'"};
326 return static_cast<Accessible*>(accessible);
329 Accessible* BridgeBase::Find(const Address& ptr) const
331 assert(ptr.GetBus() == mData->mBusName);
332 return Find(ptr.GetPath());
335 Accessible* BridgeBase::FindSelf() const
337 auto path = DBus::DBusServer::getCurrentObjectPath();
338 auto size = strlen(AtspiPath);
339 if(path.size() <= size)
341 throw std::domain_error{"invalid path '" + path + "'"};
343 if(path.substr(0, size) != AtspiPath)
345 throw std::domain_error{"invalid path '" + path + "'"};
347 if(path[size] != '/')
349 throw std::domain_error{"invalid path '" + path + "'"};
351 return Find(StripPrefix(path));
354 void BridgeBase::SetId(int id)
359 int BridgeBase::GetId()
364 auto BridgeBase::GetItems() -> DBus::ValueOrError<std::vector<CacheElementType>>
366 auto root = &mApplication;
368 std::vector<CacheElementType> res;
370 std::function<void(Accessible*)> proc =
371 [&](Accessible* item) {
372 res.emplace_back(std::move(CreateCacheElement(root)));
373 for(auto i = 0u; i < item->GetChildCount(); ++i)
375 proc(item->GetChildAtIndex(i));
382 auto BridgeBase::CreateCacheElement(Accessible* item) -> CacheElementType
389 auto root = &mApplication;
390 auto parent = item->GetParent();
392 std::vector<Address> children;
393 for(auto i = 0u; i < item->GetChildCount(); ++i)
395 children.emplace_back(item->GetChildAtIndex(i)->GetAddress());
398 return std::make_tuple(
401 parent ? parent->GetAddress() : Address{},
403 item->GetInterfaces(),
406 item->GetDescription(),
407 item->GetStates().GetRawData());