Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qspiaccessiblebridge.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
6
7#include <atspi/atspi-constants.h>
8#include <private/qguiapplication_p.h>
9#include <qpa/qplatformintegration.h>
10#include <qstring.h>
11
12#include "atspiadaptor_p.h"
13
18
19#if QT_CONFIG(accessibility)
20#include "deviceeventcontroller_adaptor.h"
21
22QT_BEGIN_NAMESPACE
23
24using namespace Qt::StringLiterals;
25using namespace QtGuiPrivate; // for D-Bus accessibility wrappers
26
27/*!
28 \class QSpiAccessibleBridge
29 \internal
30*/
31
32QSpiAccessibleBridge::QSpiAccessibleBridge()
33 : cache(nullptr), dec(nullptr), dbusAdaptor(nullptr)
34{
35 dbusConnection = new QAtSpiDBusConnection();
36 connect(dbusConnection, SIGNAL(enabledChanged(bool)), this, SLOT(enabledChanged(bool)));
37 // Now that we have connected the signal, make sure we didn't miss a change,
38 // e.g. when running as root or when AT_SPI_BUS_ADDRESS is set by hand.
39 // But do that only on next loop, once dbus is really settled.
40 QTimer::singleShot(
41 0, this, [this]{
42 if (dbusConnection->isEnabled() && dbusConnection->connection().isConnected())
43 enabledChanged(true);
44 });
45}
46
47void QSpiAccessibleBridge::enabledChanged(bool enabled)
48{
49 setActive(enabled);
50 updateStatus();
51}
52
53QSpiAccessibleBridge::~QSpiAccessibleBridge()
54{
55 delete dbusConnection;
56} // Qt currently doesn't delete plugins.
57
58QDBusConnection QSpiAccessibleBridge::dBusConnection() const
59{
60 return dbusConnection->connection();
61}
62
63void QSpiAccessibleBridge::updateStatus()
64{
65 // create the adaptor to handle everything if we are in enabled state
66 if (!dbusAdaptor && isActive()) {
67 qSpiInitializeStructTypes();
68 initializeConstantMappings();
69
70 cache = new QSpiDBusCache(dbusConnection->connection(), this);
71 dec = new DeviceEventControllerAdaptor(this);
72
73 dbusConnection->connection().registerObject(ATSPI_DBUS_PATH_DEC ""_L1, this, QDBusConnection::ExportAdaptors);
74
75 dbusAdaptor = new AtSpiAdaptor(dbusConnection, this);
76 dbusConnection->connection().registerVirtualObject(QSPI_OBJECT_PATH_ACCESSIBLE ""_L1, dbusAdaptor, QDBusConnection::SubPath);
77 dbusAdaptor->registerApplication();
78 }
79}
80
81void QSpiAccessibleBridge::notifyAccessibilityUpdate(QAccessibleEvent *event)
82{
83 if (!dbusAdaptor)
84 return;
85 if (isActive() && event->accessibleInterface())
86 dbusAdaptor->notify(event);
87}
88
89struct RoleMapping {
90 QAccessible::Role role;
91 AtspiRole spiRole;
92 const char *name;
93};
94
95static RoleMapping map[] = {
96 //: Role of an accessible object - the object is in an invalid state or could not be constructed
97 { QAccessible::NoRole, ATSPI_ROLE_INVALID, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "invalid role") },
98 //: Role of an accessible object
99 { QAccessible::TitleBar, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "title bar") },
100 //: Role of an accessible object
101 { QAccessible::MenuBar, ATSPI_ROLE_MENU_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "menu bar") },
102 //: Role of an accessible object
103 { QAccessible::ScrollBar, ATSPI_ROLE_SCROLL_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "scroll bar") },
104 //: Role of an accessible object - the grip is usually used for resizing another object
105 { QAccessible::Grip, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "grip") },
106 //: Role of an accessible object
107 { QAccessible::Sound, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "sound") },
108 //: Role of an accessible object
109 { QAccessible::Cursor, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "cursor") },
110 //: Role of an accessible object
111 { QAccessible::Caret, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "text caret") },
112 //: Role of an accessible object
113 { QAccessible::AlertMessage, ATSPI_ROLE_ALERT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "alert message") },
114 //: Role of an accessible object: a window with frame and title
115 { QAccessible::Window, ATSPI_ROLE_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "frame") },
116 //: Role of an accessible object
117 { QAccessible::Client, ATSPI_ROLE_FILLER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "filler") },
118 //: Role of an accessible object
119 { QAccessible::PopupMenu, ATSPI_ROLE_POPUP_MENU, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "popup menu") },
120 //: Role of an accessible object
121 { QAccessible::MenuItem, ATSPI_ROLE_MENU_ITEM, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "menu item") },
122 //: Role of an accessible object
123 { QAccessible::ToolTip, ATSPI_ROLE_TOOL_TIP, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tool tip") },
124 //: Role of an accessible object
125 { QAccessible::Application, ATSPI_ROLE_APPLICATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "application") },
126 //: Role of an accessible object
127 { QAccessible::Document, ATSPI_ROLE_DOCUMENT_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "document") },
128 //: Role of an accessible object
129 { QAccessible::Pane, ATSPI_ROLE_PANEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "panel") },
130 //: Role of an accessible object
131 { QAccessible::Chart, ATSPI_ROLE_CHART, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "chart") },
132 //: Role of an accessible object
133 { QAccessible::Dialog, ATSPI_ROLE_DIALOG, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "dialog") },
134 //: Role of an accessible object
135 { QAccessible::Border, ATSPI_ROLE_PANEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "panel") },
136 //: Role of an accessible object
137 { QAccessible::Grouping, ATSPI_ROLE_PANEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "panel") },
138 //: Role of an accessible object
139 { QAccessible::Separator, ATSPI_ROLE_SEPARATOR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "separator") },
140 //: Role of an accessible object
141 { QAccessible::ToolBar, ATSPI_ROLE_TOOL_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tool bar") },
142 //: Role of an accessible object
143 { QAccessible::StatusBar, ATSPI_ROLE_STATUS_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "status bar") },
144 //: Role of an accessible object
145 { QAccessible::Table, ATSPI_ROLE_TABLE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "table") },
146 //: Role of an accessible object - part of a table
147 { QAccessible::ColumnHeader, ATSPI_ROLE_TABLE_COLUMN_HEADER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "column header") },
148 //: Role of an accessible object - part of a table
149 { QAccessible::RowHeader, ATSPI_ROLE_TABLE_ROW_HEADER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "row header") },
150 //: Role of an accessible object - part of a table
151 { QAccessible::Column, ATSPI_ROLE_TABLE_CELL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "column") },
152 //: Role of an accessible object - part of a table
153 { QAccessible::Row, ATSPI_ROLE_TABLE_ROW, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "row") },
154 //: Role of an accessible object - part of a table
155 { QAccessible::Cell, ATSPI_ROLE_TABLE_CELL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "cell") },
156 //: Role of an accessible object
157 { QAccessible::Link, ATSPI_ROLE_LINK, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "link") },
158 //: Role of an accessible object
159 { QAccessible::HelpBalloon, ATSPI_ROLE_DIALOG, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "help balloon") },
160 //: Role of an accessible object - a helper dialog
161 { QAccessible::Assistant, ATSPI_ROLE_DIALOG, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "assistant") },
162 //: Role of an accessible object
163 { QAccessible::List, ATSPI_ROLE_LIST, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "list") },
164 //: Role of an accessible object
165 { QAccessible::ListItem, ATSPI_ROLE_LIST_ITEM, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "list item") },
166 //: Role of an accessible object
167 { QAccessible::Tree, ATSPI_ROLE_TREE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tree") },
168 //: Role of an accessible object
169 { QAccessible::TreeItem, ATSPI_ROLE_TABLE_CELL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "tree item") },
170 //: Role of an accessible object
171 { QAccessible::PageTab, ATSPI_ROLE_PAGE_TAB, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "page tab") },
172 //: Role of an accessible object
173 { QAccessible::PropertyPage, ATSPI_ROLE_PAGE_TAB, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "property page") },
174 //: Role of an accessible object
175 { QAccessible::Indicator, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "indicator") },
176 //: Role of an accessible object
177 { QAccessible::Graphic, ATSPI_ROLE_IMAGE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "graphic") },
178 //: Role of an accessible object
179 { QAccessible::StaticText, ATSPI_ROLE_LABEL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "label") },
180 //: Role of an accessible object
181 { QAccessible::EditableText, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "text") },
182 //: Role of an accessible object
183 { QAccessible::PushButton, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "push button") },
184 //: Role of an accessible object
185 { QAccessible::CheckBox, ATSPI_ROLE_CHECK_BOX, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "check box") },
186 //: Role of an accessible object
187 { QAccessible::RadioButton, ATSPI_ROLE_RADIO_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "radio button") },
188 //: Role of an accessible object
189 { QAccessible::ComboBox, ATSPI_ROLE_COMBO_BOX, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "combo box") },
190 //: Role of an accessible object
191 { QAccessible::ProgressBar, ATSPI_ROLE_PROGRESS_BAR, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "progress bar") },
192 //: Role of an accessible object
193 { QAccessible::Dial, ATSPI_ROLE_DIAL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "dial") },
194 //: Role of an accessible object
195 { QAccessible::HotkeyField, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "hotkey field") },
196 //: Role of an accessible object
197 { QAccessible::Slider, ATSPI_ROLE_SLIDER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "slider") },
198 //: Role of an accessible object
199 { QAccessible::SpinBox, ATSPI_ROLE_SPIN_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "spin box") },
200 //: Role of an accessible object
201 { QAccessible::Canvas, ATSPI_ROLE_CANVAS, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "canvas") },
202 //: Role of an accessible object
203 { QAccessible::Animation, ATSPI_ROLE_ANIMATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "animation") },
204 //: Role of an accessible object
205 { QAccessible::Equation, ATSPI_ROLE_TEXT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "equation") },
206 //: Role of an accessible object
207 { QAccessible::ButtonDropDown, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button with drop down") },
208 //: Role of an accessible object
209#if ATSPI_ROLE_COUNT > 130
210 { QAccessible::ButtonMenu, ATSPI_ROLE_PUSH_BUTTON_MENU, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button menu") },
211#else
212 { QAccessible::ButtonMenu, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button menu") },
213#endif
214 //: Role of an accessible object - a button that expands a grid.
215 { QAccessible::ButtonDropGrid, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button with drop down grid") },
216 //: Role of an accessible object - blank space between other objects.
217 { QAccessible::Whitespace, ATSPI_ROLE_FILLER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "space") },
218 //: Role of an accessible object
219 { QAccessible::PageTabList, ATSPI_ROLE_PAGE_TAB_LIST, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "page tab list") },
220 //: Role of an accessible object
221 { QAccessible::Clock, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "clock") },
222 //: Role of an accessible object
223 { QAccessible::Splitter, ATSPI_ROLE_SPLIT_PANE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "splitter") },
224 //: Role of an accessible object
225 { QAccessible::LayeredPane, ATSPI_ROLE_LAYERED_PANE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "layered pane") },
226 //: Role of an accessible object
227 { QAccessible::WebDocument, ATSPI_ROLE_DOCUMENT_WEB, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "web document") },
228 //: Role of an accessible object
229 { QAccessible::Paragraph, ATSPI_ROLE_PARAGRAPH, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "paragraph") },
230 //: Role of an accessible object
231 { QAccessible::Section, ATSPI_ROLE_SECTION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "section") },
232 //: Role of an accessible object
233 { QAccessible::ColorChooser, ATSPI_ROLE_COLOR_CHOOSER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "color chooser") },
234 //: Role of an accessible object
235 { QAccessible::Footer, ATSPI_ROLE_FOOTER, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "footer") },
236 //: Role of an accessible object
237 { QAccessible::Form, ATSPI_ROLE_FORM, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "form") },
238 //: Role of an accessible object
239 { QAccessible::Heading, ATSPI_ROLE_HEADING, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "heading") },
240 //: Role of an accessible object
241 { QAccessible::Note, ATSPI_ROLE_COMMENT, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "note") },
242 //: Role of an accessible object
243 { QAccessible::ComplementaryContent, ATSPI_ROLE_SECTION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "complementary content") },
244 //: Role of an accessible object
245 { QAccessible::Terminal, ATSPI_ROLE_TERMINAL, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "terminal") },
246 //: Role of an accessible object
247 { QAccessible::Desktop, ATSPI_ROLE_DESKTOP_FRAME, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "desktop") },
248 //: Role of an accessible object
249 { QAccessible::Notification, ATSPI_ROLE_NOTIFICATION, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "notification") },
250 //: Role of an accessible object
251 { QAccessible::BlockQuote, ATSPI_ROLE_BLOCK_QUOTE, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "block quote") },
252 //: Role of an accessible object
253 { QAccessible::UserRole, ATSPI_ROLE_UNKNOWN, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "unknown") }
254};
255
256void QSpiAccessibleBridge::initializeConstantMappings()
257{
258 for (uint i = 0; i < sizeof(map) / sizeof(RoleMapping); ++i)
259 m_spiRoleMapping.insert(map[i].role, RoleNames(map[i].spiRole, QLatin1StringView(map[i].name), tr(map[i].name)));
260
261 // -1 because we have button duplicated, as PushButton and Button.
262 Q_ASSERT_X(m_spiRoleMapping.size() ==
263 QAccessible::staticMetaObject.enumerator(
264 QAccessible::staticMetaObject.indexOfEnumerator("Role")).keyCount() - 1,
265 "", "Handle all QAccessible::Role members in qSpiRoleMapping");
266}
267
268QSpiAccessibleBridge *QSpiAccessibleBridge::instance()
269{
270 if (auto integration = QGuiApplicationPrivate::platformIntegration()) {
271 if (auto accessibility = integration->accessibility())
272 return static_cast<QSpiAccessibleBridge *>(accessibility);
273 }
274 return nullptr;
275}
276
277RoleNames QSpiAccessibleBridge::namesForRole(QAccessible::Role role)
278{
279 auto brigde = QSpiAccessibleBridge::instance();
280 return brigde ? brigde->spiRoleNames().value(role) : RoleNames();
281}
282
283QT_END_NAMESPACE
284
285#include "moc_qspiaccessiblebridge_p.cpp"
286#endif // QT_CONFIG(accessibility)