/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <unordered_map>
// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/actor-accessible.h>
#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/internal/accessibility/bridge/accessibility-common.h>
#include <dali/internal/accessibility/bridge/bridge-accessible.h>
#include <dali/internal/accessibility/bridge/bridge-action.h>
+#include <dali/internal/accessibility/bridge/bridge-application.h>
#include <dali/internal/accessibility/bridge/bridge-collection.h>
#include <dali/internal/accessibility/bridge/bridge-component.h>
#include <dali/internal/accessibility/bridge/bridge-editable-text.h>
-#include <dali/internal/accessibility/bridge/bridge-hypertext.h>
#include <dali/internal/accessibility/bridge/bridge-hyperlink.h>
+#include <dali/internal/accessibility/bridge/bridge-hypertext.h>
#include <dali/internal/accessibility/bridge/bridge-object.h>
#include <dali/internal/accessibility/bridge/bridge-selection.h>
+#include <dali/internal/accessibility/bridge/bridge-socket.h>
+#include <dali/internal/accessibility/bridge/bridge-table-cell.h>
+#include <dali/internal/accessibility/bridge/bridge-table.h>
#include <dali/internal/accessibility/bridge/bridge-text.h>
#include <dali/internal/accessibility/bridge/bridge-value.h>
-#include <dali/internal/accessibility/bridge/bridge-application.h>
-#include <dali/internal/accessibility/bridge/dummy-atspi.h>
+#include <dali/internal/accessibility/bridge/dummy/dummy-atspi.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
#include <dali/internal/system/common/environment-variables.h>
namespace // unnamed namespace
{
-
const int RETRY_INTERVAL = 1000;
} // unnamed namespace
public BridgeSelection,
public BridgeApplication,
public BridgeHypertext,
- public BridgeHyperlink
+ public BridgeHyperlink,
+ public BridgeSocket,
+ public BridgeTable,
+ public BridgeTableCell
{
- DBus::DBusClient mAccessibilityStatusClient;
- DBus::DBusClient mRegistryClient;
- DBus::DBusClient mDirectReadingClient;
- bool mIsScreenReaderEnabled = false;
- bool mIsEnabled = false;
- bool mIsShown = false;
- std::unordered_map<int32_t, std::function<void(std::string)>> mDirectReadingCallbacks;
+ DBus::DBusClient mAccessibilityStatusClient{};
+ DBus::DBusClient mRegistryClient{};
+ DBus::DBusClient mDirectReadingClient{};
+ bool mIsScreenReaderEnabled{false};
+ bool mIsEnabled{false};
+ bool mIsApplicationRunning{false};
+ std::unordered_map<int32_t, std::function<void(std::string)>> mDirectReadingCallbacks{};
Dali::Actor mHighlightedActor;
- std::function<void(Dali::Actor)> mHighlightClearAction;
- Dali::CallbackBase* mIdleCallback = NULL;
+ std::function<void(Dali::Actor)> mHighlightClearAction{nullptr};
+ Dali::CallbackBase* mIdleCallback{};
Dali::Timer mInitializeTimer;
Dali::Timer mReadIsEnabledTimer;
Dali::Timer mReadScreenReaderEnabledTimer;
+ Dali::Timer mForceUpTimer;
+ std::string mPreferredBusName;
+ std::map<uint32_t, std::shared_ptr<Accessible>> mAccessibles; // Actor.ID to Accessible map
public:
- BridgeImpl()
+ BridgeImpl() = default;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::AddAccessible()
+ */
+ void AddAccessible(uint32_t actorId, std::shared_ptr<Accessible> accessible) override
{
+ mAccessibles[actorId] = std::move(accessible);
}
/**
- * @copydoc Dali::Accessibility::Bridge::Emit()
+ * @copydoc Dali::Accessibility::Bridge::RemoveAccessible()
*/
- Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
+ void RemoveAccessible(uint32_t actorId) override
{
- if(!IsUp())
- {
- return Consumed::NO;
- }
+ mAccessibles.erase(actorId);
+ }
- unsigned int keyType = 0;
+ /**
+ * @copydoc Dali::Accessibility::Bridge::GetAccessible()
+ */
+ std::shared_ptr<Accessible> GetAccessible(Dali::Actor actor) const override
+ {
+ uint32_t actorId = actor.GetProperty<int>(Dali::Actor::Property::ID);
+ auto iter = mAccessibles.find(actorId);
+ return iter != mAccessibles.end() ? iter->second : nullptr;
+ }
- switch(type)
+ /**
+ * @copydoc Dali::Accessibility::Bridge::ShouldIncludeHidden()
+ */
+ bool ShouldIncludeHidden() const override
+ {
+ return mApplication.mShouldIncludeHidden;
+ }
+
+ void NotifyIncludeHiddenChanged() override
+ {
+ for(const auto& iter : mAccessibles)
{
- case KeyEventType::KEY_PRESSED:
+ const auto& accessible = iter.second;
+ if(accessible->IsHidden())
{
- keyType = 0;
- break;
+ auto* parent = dynamic_cast<ActorAccessible*>(accessible->GetParent());
+ if(parent)
+ {
+ parent->OnChildrenChanged();
+ }
}
- case KeyEventType::KEY_RELEASED:
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitKeyEvent()
+ */
+ bool EmitKeyEvent(Dali::KeyEvent keyEvent, std::function<void(Dali::KeyEvent, bool)> callback) override
+ {
+ using ArgumentTypes = std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>;
+
+ static const char* methodName = "NotifyListenersSync";
+
+ if(!IsUp())
+ {
+ return false;
+ }
+
+ uint32_t keyType = (keyEvent.GetState() == Dali::KeyEvent::DOWN ? 0U : 1U);
+ auto timeStamp = static_cast<std::int32_t>(keyEvent.GetTime());
+ bool isText = !keyEvent.GetKeyString().empty();
+
+ ArgumentTypes arguments(keyType, 0, keyEvent.GetKeyCode(), 0, timeStamp, keyEvent.GetKeyName(), isText);
+
+ auto functor = [keyEvent = std::move(keyEvent), callback = std::move(callback)](DBus::ValueOrError<bool> reply) {
+ bool consumed = false;
+
+ if(!reply)
{
- keyType = 1;
- break;
+ DALI_LOG_ERROR("%s call failed: %s", methodName, reply.getError().message.c_str());
}
- default:
+ else
{
- return Consumed::NO;
+ consumed = std::get<0>(reply.getValues());
}
- }
- auto methodObject = mRegistryClient.method<bool(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>)>("NotifyListenersSync");
- auto result = methodObject.call(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>{keyType, 0, static_cast<int32_t>(keyCode), 0, static_cast<int32_t>(timeStamp), keyName, isText ? 1 : 0});
- if(!result)
- {
- LOG() << result.getError().message;
- return Consumed::NO;
- }
- return std::get<0>(result) ? Consumed::YES : Consumed::NO;
+ callback(std::move(keyEvent), consumed);
+ };
+
+ mRegistryClient.method<bool(ArgumentTypes)>(methodName).asyncCall(std::move(functor), arguments);
+
+ return true;
}
/**
mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
if(!msg)
{
- LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+ LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
}
},
- true);
+ true);
}
/**
mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
if(!msg)
{
- LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+ LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
}
},
- false);
+ false);
}
/**
mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
if(!msg)
{
- LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+ LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
}
},
- alsoNonDiscardable);
+ alsoNonDiscardable);
}
/**
mDirectReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
if(!msg)
{
- LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+ LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
}
else if(callback)
{
mDirectReadingCallbacks.emplace(std::get<2>(msg), callback);
}
},
- text,
- discardable);
+ text,
+ discardable);
}
/**
mData->mHighlightActor = {};
mDisabledSignal.Emit();
+ UnembedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"});
+ ReleaseBusName(mPreferredBusName);
}
+
mHighlightedActor = {};
mHighlightClearAction = {};
BridgeAccessible::ForceDown();
- mRegistryClient = {};
- mDirectReadingClient = {};
+ mRegistryClient = {};
+ mDirectReadingClient = {};
mDirectReadingCallbacks.clear();
mApplication.mChildren.clear();
- mApplication.mWindows.clear();
+ ClearTimer();
}
- void StopTimer()
+ void ClearTimer()
{
if(mInitializeTimer)
{
mInitializeTimer.Stop();
+ mInitializeTimer.Reset();
}
if(mReadIsEnabledTimer)
{
mReadIsEnabledTimer.Stop();
+ mReadIsEnabledTimer.Reset();
}
if(mReadScreenReaderEnabledTimer)
{
mReadScreenReaderEnabledTimer.Stop();
+ mReadScreenReaderEnabledTimer.Reset();
+ }
+
+ if(mForceUpTimer)
+ {
+ mForceUpTimer.Stop();
+ mForceUpTimer.Reset();
}
}
{
if(mData)
{
+ // The ~Window() after this point cannot emit DESTROY, because Bridge is not available. So emit DESTROY here.
+ for(auto windowAccessible : mApplication.mChildren)
+ {
+ BridgeObject::Emit(windowAccessible, WindowEvent::DESTROY);
+ }
mData->mCurrentlyHighlightedActor = {};
mData->mHighlightActor = {};
}
ForceDown();
- StopTimer();
if((NULL != mIdleCallback) && Dali::Adaptor::IsAvailable())
{
Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
}
- mAccessibilityStatusClient = {};
- mDbusServer = {};
- mConnectionPtr = {};
+ mAccessibilityStatusClient = {};
+ mDbusServer = {};
+ mConnectionPtr = {};
+ }
+
+ bool ForceUpTimerCallback()
+ {
+ if(ForceUp() != ForceUpResult::FAILED)
+ {
+ return false;
+ }
+ return true;
}
/**
*/
ForceUpResult ForceUp() override
{
- if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
+ auto forceUpResult = BridgeAccessible::ForceUp();
+ if(forceUpResult == ForceUpResult::ALREADY_UP)
+ {
+ return forceUpResult;
+ }
+ else if(forceUpResult == ForceUpResult::FAILED)
{
- return ForceUpResult::ALREADY_UP;
+ if(!mForceUpTimer)
+ {
+ mForceUpTimer = Dali::Timer::New(RETRY_INTERVAL);
+ mForceUpTimer.TickSignal().Connect(this, &BridgeImpl::ForceUpTimerCallback);
+ mForceUpTimer.Start();
+ }
+ return forceUpResult;
}
BridgeObject::RegisterInterfaces();
BridgeApplication::RegisterInterfaces();
BridgeHypertext::RegisterInterfaces();
BridgeHyperlink::RegisterInterfaces();
+ BridgeSocket::RegisterInterfaces();
+ BridgeTable::RegisterInterfaces();
+ BridgeTableCell::RegisterInterfaces();
RegisterOnBridge(&mApplication);
- mRegistryClient = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
+ mRegistryClient = {AtspiDbusNameRegistry, AtspiDbusPathDec, Accessible::GetInterfaceName(AtspiInterface::DEVICE_EVENT_CONTROLLER), mConnectionPtr};
mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
}
});
- auto proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, mConnectionPtr};
- Address root{"", "root"};
- auto res = proxy.method<Address(Address)>("Embed").call(root);
- if(!res)
- {
- LOG() << "Call to Embed failed: " << res.getError().message;
- }
- assert(res);
-
- mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
+ RequestBusName(mPreferredBusName);
+ auto parentAddress = EmbedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"});
+ mApplication.mParent.SetAddress(std::move(parentAddress));
mEnabledSignal.Emit();
- if(mIsShown)
+ return ForceUpResult::JUST_STARTED;
+ }
+
+ /**
+ * @brief Sends a signal to dbus that the window is created.
+ *
+ * @param[in] window The window to be created
+ * @see BridgeObject::Emit()
+ */
+ void EmitCreated(Dali::Window window)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
{
- 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.
+ windowAccessible->Emit(WindowEvent::CREATE, 0);
}
-
- return ForceUpResult::JUST_STARTED;
}
/**
}
/**
+ * @brief Sends a signal to dbus that the window is minimized.
+ *
+ * @param[in] window The window to be minimized
+ * @see BridgeObject::Emit()
+ */
+ void EmitMinimize(Dali::Window window)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
+ {
+ windowAccessible->Emit(WindowEvent::MINIMIZE, 0);
+ }
+ }
+
+ /**
+ * @brief Sends a signal to dbus that the window is restored.
+ *
+ * @param[in] window The window to be restored
+ * @param[in] detail Restored window state
+ * @see BridgeObject::Emit()
+ */
+ void EmitRestore(Dali::Window window, Dali::Accessibility::WindowRestoreType detail)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
+ {
+ windowAccessible->Emit(WindowEvent::RESTORE, static_cast<unsigned int>(detail));
+ }
+ }
+
+ /**
+ * @brief Sends a signal to dbus that the window is maximized.
+ *
+ * @param[in] window The window to be maximized
+ * @see BridgeObject::Emit()
+ */
+ void EmitMaximize(Dali::Window window)
+ {
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
+ {
+ windowAccessible->Emit(WindowEvent::MAXIMIZE, 0);
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowCreated()
+ */
+ void WindowCreated(Dali::Window window) override
+ {
+ if(IsUp())
+ {
+ EmitCreated(window);
+ }
+ }
+
+ /**
* @copydoc Dali::Accessibility::Bridge::WindowShown()
*/
void WindowShown(Dali::Window window) override
{
- if(!mIsShown && IsUp())
+ if(IsUp())
{
EmitShown(window);
}
- mIsShown = true;
}
/**
*/
void WindowHidden(Dali::Window window) override
{
- if(mIsShown && IsUp())
+ if(IsUp())
{
EmitHidden(window);
}
- mIsShown = false;
}
/**
*/
void WindowFocused(Dali::Window window) override
{
- if(mIsShown && IsUp())
+ if(IsUp())
{
EmitActivate(window);
}
*/
void WindowUnfocused(Dali::Window window) override
{
- if(mIsShown && IsUp())
+ if(IsUp())
{
EmitDeactivate(window);
}
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowMinimized()
+ */
+ void WindowMinimized(Dali::Window window) override
+ {
+ if(IsUp())
+ {
+ EmitMinimize(window);
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowRestored()
+ */
+ void WindowRestored(Dali::Window window, WindowRestoreType detail) override
+ {
+ if(IsUp())
+ {
+ EmitRestore(window, detail);
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowMaximized()
+ */
+ void WindowMaximized(Dali::Window window) override
+ {
+ if(IsUp())
+ {
+ EmitMaximize(window);
+ }
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::ApplicationPaused()
+ */
+ void ApplicationPaused() override
+ {
+ mIsApplicationRunning = false;
+ SwitchBridge();
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::ApplicationResumed()
+ */
+ void ApplicationResumed() override
+ {
+ mIsApplicationRunning = true;
+ SwitchBridge();
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::SuppressScreenReader()
+ */
+ void SuppressScreenReader(bool suppress) override
+ {
+ if(mIsScreenReaderSuppressed == suppress)
+ {
+ return;
+ }
+ mIsScreenReaderSuppressed = suppress;
+ ReadScreenReaderEnabledProperty();
+ }
+
+ void SwitchBridge()
+ {
+ bool isScreenReaderEnabled = mIsScreenReaderEnabled && !mIsScreenReaderSuppressed;
+
+ if((isScreenReaderEnabled || mIsEnabled) && mIsApplicationRunning)
+ {
+ ForceUp();
+ }
+ else
+ {
+ ForceDown();
+ }
+ }
+
bool ReadIsEnabledTimerCallback()
{
ReadIsEnabledProperty();
}
return;
}
- mIsEnabled = std::get<0>(msg);
- if(mIsEnabled)
+
+ if(mReadIsEnabledTimer)
{
- ForceUp();
+ mReadIsEnabledTimer.Stop();
+ mReadIsEnabledTimer.Reset();
}
+
+ mIsEnabled = std::get<0>(msg);
+ SwitchBridge();
});
}
{
mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
mIsEnabled = res;
- if(mIsScreenReaderEnabled || mIsEnabled)
- {
- ForceUp();
- }
- else
- {
- ForceDown();
- }
+ SwitchBridge();
});
}
void ReadScreenReaderEnabledProperty()
{
+ // can be true because of SuppressScreenReader before init
+ if(!mAccessibilityStatusClient)
+ {
+ return;
+ }
+
mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
if(!msg)
{
}
return;
}
- mIsScreenReaderEnabled = std::get<0>(msg);
- if(mIsScreenReaderEnabled)
+
+ if(mReadScreenReaderEnabledTimer)
{
- ForceUp();
+ mReadScreenReaderEnabledTimer.Stop();
+ mReadScreenReaderEnabledTimer.Reset();
}
+
+ mIsScreenReaderEnabled = std::get<0>(msg);
+ SwitchBridge();
});
}
+ void EmitScreenReaderEnabledSignal()
+ {
+ if(mIsScreenReaderEnabled)
+ {
+ mScreenReaderEnabledSignal.Emit();
+ }
+ else
+ {
+ mScreenReaderDisabledSignal.Emit();
+ }
+ }
+
void ListenScreenReaderEnabledProperty()
{
mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
mIsScreenReaderEnabled = res;
- if(mIsScreenReaderEnabled || mIsEnabled)
- {
- ForceUp();
- }
- else
- {
- ForceDown();
- }
+ EmitScreenReaderEnabledSignal();
+ SwitchBridge();
});
}
{
mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
- if (!mAccessibilityStatusClient)
+ if(!mAccessibilityStatusClient)
{
DALI_LOG_ERROR("Accessibility Status DbusClient is not ready\n");
return false;
bool InitializeTimerCallback()
{
- if ( InitializeAccessibilityStatusClient() )
+ if(InitializeAccessibilityStatusClient())
{
ReadAndListenProperties();
return false;
bool OnIdleSignal()
{
- if ( InitializeAccessibilityStatusClient() )
+ if(InitializeAccessibilityStatusClient())
{
ReadAndListenProperties();
mIdleCallback = NULL;
*/
void Initialize() override
{
- if ( InitializeAccessibilityStatusClient() )
+ if(InitializeAccessibilityStatusClient())
{
ReadAndListenProperties();
return;
}
// Initialize failed. Try it again on Idle
- if( Dali::Adaptor::IsAvailable() )
+ if(Dali::Adaptor::IsAvailable())
{
Dali::Adaptor& adaptor = Dali::Adaptor::Get();
- if( NULL == mIdleCallback )
+ if(NULL == mIdleCallback)
{
- mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
- adaptor.AddIdle( mIdleCallback, true );
+ mIdleCallback = MakeCallback(this, &BridgeImpl::OnIdleSignal);
+ if(DALI_UNLIKELY(!adaptor.AddIdle(mIdleCallback, true)))
+ {
+ DALI_LOG_ERROR("Fail to add idle callback for bridge initialize. Call it synchronously.\n");
+ OnIdleSignal();
+ }
}
}
}
{
return mIsEnabled;
}
+
+ Address EmbedSocket(const Address& plug, const Address& socket) override
+ {
+ auto client = CreateSocketClient(socket);
+ auto reply = client.method<Address(Address)>("Embed").call(plug);
+
+ if(!reply)
+ {
+ DALI_LOG_ERROR("Failed to embed socket %s: %s", socket.ToString().c_str(), reply.getError().message.c_str());
+ return {};
+ }
+
+ return std::get<0>(reply.getValues());
+ }
+
+ void UnembedSocket(const Address& plug, const Address& socket) override
+ {
+ auto client = CreateSocketClient(socket);
+
+ client.method<void(Address)>("Unembed").asyncCall([](DBus::ValueOrError<void>) {}, plug);
+ }
+
+ void SetSocketOffset(ProxyAccessible* socket, std::int32_t x, std::int32_t y) override
+ {
+ AddCoalescableMessage(CoalescableMessages::SET_OFFSET, socket, 1.0f, [=]() {
+ auto client = CreateSocketClient(socket->GetAddress());
+
+ client.method<void(std::int32_t, std::int32_t)>("SetOffset").asyncCall([](DBus::ValueOrError<void>) {}, x, y);
+ });
+ }
+
+ void SetExtentsOffset(std::int32_t x, std::int32_t y) override
+ {
+ if(mData)
+ {
+ mData->mExtentsOffset = {x, y};
+ }
+ }
+
+ void SetPreferredBusName(std::string_view preferredBusName) override
+ {
+ if(preferredBusName == mPreferredBusName)
+ {
+ return;
+ }
+
+ std::string oldPreferredBusName = std::move(mPreferredBusName);
+ mPreferredBusName = std::string{preferredBusName};
+
+ if(IsUp())
+ {
+ ReleaseBusName(oldPreferredBusName);
+ RequestBusName(mPreferredBusName);
+ }
+ // else: request/release will be handled by ForceUp/ForceDown, respectively
+ }
+
+private:
+ DBus::DBusClient CreateSocketClient(const Address& socket)
+ {
+ return {socket.GetBus(), ATSPI_PREFIX_PATH + socket.GetPath(), Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr};
+ }
+
+ void RequestBusName(const std::string& busName)
+ {
+ if(busName.empty())
+ {
+ return;
+ }
+
+ DBus::requestBusName(mConnectionPtr, busName);
+ }
+
+ void ReleaseBusName(const std::string& busName)
+ {
+ if(busName.empty())
+ {
+ return;
+ }
+
+ DBus::releaseBusName(mConnectionPtr, busName);
+ }
}; // BridgeImpl
namespace // unnamed namespace
{
-
bool INITIALIZED_BRIDGE = false;
/**
* @return The BridgeImpl instance
* @note This method is to check environment variable first. If ATSPI is disable using env, it returns dummy bridge instance.
*/
-Bridge* CreateBridge()
+std::shared_ptr<Bridge> CreateBridge()
{
INITIALIZED_BRIDGE = true;
return Dali::Accessibility::DummyBridge::GetInstance();
}
- return new BridgeImpl;
+ return std::make_shared<BridgeImpl>();
}
catch(const std::exception&)
{
// Dali::Accessibility::Bridge class implementation
-Bridge* Bridge::GetCurrentBridge()
+std::shared_ptr<Bridge> Bridge::GetCurrentBridge()
{
- static Bridge* bridge;
+ static std::shared_ptr<Bridge> bridge;
if(bridge)
{
auto window = Dali::DevelWindow::Get(rootLayer);
auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
- auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+ auto accessible = Accessibility::Accessible::Get(rootLayer);
- auto* bridge = Bridge::GetCurrentBridge();
+ auto bridge = Bridge::GetCurrentBridge();
bridge->AddTopLevelWindow(accessible);
bridge->SetApplicationName(applicationName);
bridge->Initialize();
bridge->WindowShown(window);
}
}
+
+std::string Bridge::MakeBusNameForWidget(std::string_view widgetInstanceId, int widgetProcessId)
+{
+ // The bus name should consist of dot-separated alphanumeric elements, e.g. "com.example.BusName123".
+ // Allowed characters in each element: "[A-Z][a-z][0-9]_-", but no element may start with a digit.
+
+ static const char prefix[] = "elm.atspi.proxy.socket-";
+ static const char underscore = '_';
+
+ std::stringstream tmp;
+
+ tmp << prefix;
+
+ for(char ch : widgetInstanceId)
+ {
+ tmp << (!std::isalnum(ch) && ch != '_' && ch != '-' && ch != '.' ? underscore : ch);
+ }
+
+ tmp << '-' << widgetProcessId;
+
+ return tmp.str();
+}