[dali_2.3.38] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-object.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/accessibility/bridge/bridge-object.h>
20
21 // EXTERNAL INCLUDES
22 #include <iostream>
23 #include <string>
24 #include <string_view>
25 #include <unordered_map>
26
27 using namespace Dali::Accessibility;
28
29 namespace
30 {
31 inline std::string GetAccessiblePath(Accessible* accessible)
32 {
33   auto address = accessible->GetAddress();
34   return address ? ATSPI_PREFIX_PATH + address.GetPath() : ATSPI_NULL_PATH;
35 }
36 } // namespace
37
38 BridgeObject::BridgeObject()
39 {
40 }
41
42 void BridgeObject::RegisterInterfaces()
43 {
44   // DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT)};
45   // mStateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
46   // mDbusServer.addInterface("/", desc, true);
47 }
48
49 void BridgeObject::EmitActiveDescendantChanged(Accessible* obj, Accessible* child)
50 {
51   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::ACTIVE_DESCENDANT_CHANGED] || child->IsHidden())
52   {
53     return;
54   }
55
56   auto index = child->GetIndexInParent();
57
58   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<Address>, Address>(
59     GetAccessiblePath(obj),
60     Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
61     "ActiveDescendantChanged",
62     "",
63     index,
64     0,
65     {child->GetAddress()},
66     {"", "root"});
67 }
68
69 void BridgeObject::Emit(std::shared_ptr<Accessible> obj, ObjectPropertyChangeEvent event)
70 {
71   static const std::unordered_map<ObjectPropertyChangeEvent, std::string_view> eventMap{
72     {ObjectPropertyChangeEvent::NAME, "accessible-name"},
73     {ObjectPropertyChangeEvent::DESCRIPTION, "accessible-description"},
74     {ObjectPropertyChangeEvent::VALUE, "accessible-value"},
75     {ObjectPropertyChangeEvent::PARENT, "accessible-parent"},
76     {ObjectPropertyChangeEvent::ROLE, "accessible-role"},
77   };
78
79   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::PROPERTY_CHANGED])
80   {
81     return;
82   }
83
84   auto eventName = eventMap.find(event);
85
86   if(eventName != eventMap.end())
87   {
88     AddCoalescableMessage(static_cast<CoalescableMessages>(static_cast<int>(CoalescableMessages::PROPERTY_CHANGED_BEGIN) + static_cast<int>(event)), obj.get(), 1.0f, [weakObj = std::weak_ptr<Accessible>(obj), eventName, this]() {
89       if(auto obj = weakObj.lock())
90       {
91         mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
92           GetAccessiblePath(obj.get()),
93           Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
94           "PropertyChange",
95           std::string{eventName->second},
96           0,
97           0,
98           {0},
99           {"", "root"});
100       }
101     });
102   }
103 }
104
105 void BridgeObject::Emit(Accessible* obj, WindowEvent event, unsigned int detail)
106 {
107   static const std::unordered_map<WindowEvent, std::string_view> eventMap{
108     {WindowEvent::PROPERTY_CHANGE, "PropertyChange"},
109     {WindowEvent::MINIMIZE, "Minimize"},
110     {WindowEvent::MAXIMIZE, "Maximize"},
111     {WindowEvent::RESTORE, "Restore"},
112     {WindowEvent::CLOSE, "Close"},
113     {WindowEvent::CREATE, "Create"},
114     {WindowEvent::REPARENT, "Reparent"},
115     {WindowEvent::DESKTOP_CREATE, "DesktopCreate"},
116     {WindowEvent::DESKTOP_DESTROY, "DesktopDestroy"},
117     {WindowEvent::DESTROY, "Destroy"},
118     {WindowEvent::ACTIVATE, "Activate"},
119     {WindowEvent::DEACTIVATE, "Deactivate"},
120     {WindowEvent::RAISE, "Raise"},
121     {WindowEvent::LOWER, "Lower"},
122     {WindowEvent::MOVE, "Move"},
123     {WindowEvent::RESIZE, "Resize"},
124     {WindowEvent::SHADE, "Shade"},
125     {WindowEvent::UU_SHADE, "uUshade"},
126     {WindowEvent::RESTYLE, "Restyle"},
127     {WindowEvent::POST_RENDER, "PostRender"},
128   };
129
130   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::WINDOW_CHANGED])
131   {
132     return;
133   }
134
135   auto eventName = eventMap.find(event);
136
137   if(eventName != eventMap.end())
138   {
139     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
140       GetAccessiblePath(obj),
141       Accessible::GetInterfaceName(AtspiInterface::EVENT_WINDOW),
142       std::string{eventName->second},
143       "",
144       detail,
145       0,
146       {0},
147       {"", "root"});
148   }
149 }
150
151 void BridgeObject::EmitStateChanged(std::shared_ptr<Accessible> obj, State state, int newValue, int reserved)
152 {
153   static const std::unordered_map<State, std::string_view> stateMap{
154     {State::INVALID, "invalid"},
155     {State::ACTIVE, "active"},
156     {State::ARMED, "armed"},
157     {State::BUSY, "busy"},
158     {State::CHECKED, "checked"},
159     {State::COLLAPSED, "collapsed"},
160     {State::DEFUNCT, "defunct"},
161     {State::EDITABLE, "editable"},
162     {State::ENABLED, "enabled"},
163     {State::EXPANDABLE, "expandable"},
164     {State::EXPANDED, "expanded"},
165     {State::FOCUSABLE, "focusable"},
166     {State::FOCUSED, "focused"},
167     {State::HAS_TOOLTIP, "has-tooltip"},
168     {State::HORIZONTAL, "horizontal"},
169     {State::ICONIFIED, "iconified"},
170     {State::MODAL, "modal"},
171     {State::MULTI_LINE, "multi-line"},
172     {State::MULTI_SELECTABLE, "multiselectable"},
173     {State::OPAQUE, "opaque"},
174     {State::PRESSED, "pressed"},
175     {State::RESIZEABLE, "resizable"},
176     {State::SELECTABLE, "selectable"},
177     {State::SELECTED, "selected"},
178     {State::SENSITIVE, "sensitive"},
179     {State::SHOWING, "showing"},
180     {State::SINGLE_LINE, "single-line"},
181     {State::STALE, "stale"},
182     {State::TRANSIENT, "transient"},
183     {State::VERTICAL, "vertical"},
184     {State::VISIBLE, "visible"},
185     {State::MANAGES_DESCENDANTS, "manages-descendants"},
186     {State::INDETERMINATE, "indeterminate"},
187     {State::REQUIRED, "required"},
188     {State::TRUNCATED, "truncated"},
189     {State::ANIMATED, "animated"},
190     {State::INVALID_ENTRY, "invalid-entry"},
191     {State::SUPPORTS_AUTOCOMPLETION, "supports-autocompletion"},
192     {State::SELECTABLE_TEXT, "selectable-text"},
193     {State::IS_DEFAULT, "is-default"},
194     {State::VISITED, "visited"},
195     {State::CHECKABLE, "checkable"},
196     {State::HAS_POPUP, "has-popup"},
197     {State::READ_ONLY, "read-only"},
198     {State::HIGHLIGHTED, "highlighted"},
199     {State::HIGHLIGHTABLE, "highlightable"},
200   };
201
202   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::STATE_CHANGED]) // separate ?
203   {
204     return;
205   }
206
207   auto stateName = stateMap.find(state);
208
209   if(stateName != stateMap.end())
210   {
211     AddCoalescableMessage(static_cast<CoalescableMessages>(static_cast<int>(CoalescableMessages::STATE_CHANGED_BEGIN) + static_cast<int>(state)), obj.get(), 1.0f, [weakObj = std::weak_ptr<Accessible>(obj), stateName, newValue, reserved, this]() {
212       if(auto obj = weakObj.lock())
213       {
214         mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
215           GetAccessiblePath(obj.get()),
216           Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
217           "StateChanged",
218           std::string{stateName->second},
219           newValue,
220           reserved,
221           {0},
222           {"", "root"});
223       }
224     });
225   }
226 }
227
228 void BridgeObject::EmitBoundsChanged(std::shared_ptr<Accessible> obj, Dali::Rect<> rect)
229 {
230   if(!IsUp() || !IsBoundsChangedEventAllowed || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::BOUNDS_CHANGED])
231   {
232     return;
233   }
234
235   AddCoalescableMessage(CoalescableMessages::BOUNDS_CHANGED, obj.get(), 1.0f, [weakObj = std::weak_ptr<Accessible>(obj), rect = std::move(rect), this]() {
236     if(auto obj = weakObj.lock())
237     {
238       DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> > tmp{
239         std::tuple<int32_t, int32_t, int32_t, int32_t>{rect.x, rect.y, rect.width, rect.height}};
240
241       mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> >, Address>(
242         GetAccessiblePath(obj.get()),
243         Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
244         "BoundsChanged",
245         "",
246         0,
247         0,
248         tmp,
249         {"", "root"});
250     }
251   });
252 }
253
254 void BridgeObject::EmitPostRender(std::shared_ptr<Accessible> obj)
255 {
256   if(!IsUp() || obj->IsHidden())
257   {
258     return;
259   }
260
261   AddCoalescableMessage(CoalescableMessages::POST_RENDER, obj.get(), 0.5f, [weakObj = std::weak_ptr<Accessible>(obj), this]() {
262     if(auto obj = weakObj.lock())
263     {
264       Emit(obj.get(), WindowEvent::POST_RENDER);
265     }
266   });
267 }
268
269 void BridgeObject::EmitCursorMoved(Accessible* obj, unsigned int cursorPosition)
270 {
271   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CARET_MOVED])
272   {
273     return;
274   }
275
276   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
277     GetAccessiblePath(obj),
278     Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
279     "TextCaretMoved",
280     "",
281     cursorPosition,
282     0,
283     {0},
284     {"", "root"});
285 }
286
287 void BridgeObject::EmitTextChanged(Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string& content)
288 {
289   static const std::unordered_map<TextChangedState, std::string_view> stateMap{
290     {TextChangedState::INSERTED, "insert"},
291     {TextChangedState::DELETED, "delete"},
292   };
293
294   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CHANGED])
295   {
296     return;
297   }
298
299   auto stateName = stateMap.find(state);
300
301   if(stateName != stateMap.end())
302   {
303     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::string>, Address>(
304       GetAccessiblePath(obj),
305       Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
306       "TextChanged",
307       std::string{stateName->second},
308       position,
309       length,
310       {content},
311       {"", "root"});
312   }
313 }
314
315 void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type)
316 {
317   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::MOVED_OUT])
318   {
319     return;
320   }
321
322   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
323     GetAccessiblePath(obj),
324     Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
325     "MoveOuted",
326     "",
327     static_cast<int>(type),
328     0,
329     {0},
330     {"", "root"});
331 }
332
333 void BridgeObject::EmitSocketAvailable(Accessible* obj)
334 {
335   if(!IsUp() || obj->IsHidden()) //TODO Suppress SocketAvailable event
336   {
337     return;
338   }
339
340   mDbusServer.emit2<Address, Address>(
341     GetAccessiblePath(obj),
342     Accessible::GetInterfaceName(AtspiInterface::SOCKET),
343     "Available",
344     obj->GetAddress(),
345     {"", "root"});
346 }
347
348 void BridgeObject::EmitScrollStarted(Accessible* obj)
349 {
350   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::SCROLL_STARTED])
351   {
352     return;
353   }
354
355   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
356     GetAccessiblePath(obj),
357     Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
358     "ScrollStarted",
359     "",
360     0,
361     0,
362     {0},
363     {"", "root"});
364 }
365
366 void BridgeObject::EmitScrollFinished(Accessible* obj)
367 {
368   if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::SCROLL_FINISHED])
369   {
370     return;
371   }
372
373   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
374     GetAccessiblePath(obj),
375     Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
376     "ScrollFinished",
377     "",
378     0,
379     0,
380     {0},
381     {"", "root"});
382 }