Changeset View
Changeset View
Standalone View
Standalone View
debug_console.cpp
Show All 30 Lines | |||||
31 | #include <KWayland/Server/buffer_interface.h> | 31 | #include <KWayland/Server/buffer_interface.h> | ||
32 | #include <KWayland/Server/clientconnection.h> | 32 | #include <KWayland/Server/clientconnection.h> | ||
33 | #include <KWayland/Server/subcompositor_interface.h> | 33 | #include <KWayland/Server/subcompositor_interface.h> | ||
34 | #include <KWayland/Server/surface_interface.h> | 34 | #include <KWayland/Server/surface_interface.h> | ||
35 | // frameworks | 35 | // frameworks | ||
36 | #include <KLocalizedString> | 36 | #include <KLocalizedString> | ||
37 | #include <NETWM> | 37 | #include <NETWM> | ||
38 | // Qt | 38 | // Qt | ||
39 | #include <QMouseEvent> | ||||
39 | #include <QMetaProperty> | 40 | #include <QMetaProperty> | ||
40 | #include <QMetaType> | 41 | #include <QMetaType> | ||
41 | 42 | | |||
42 | namespace KWin | 43 | namespace KWin | ||
43 | { | 44 | { | ||
44 | 45 | | |||
46 | | ||||
47 | static QString tableHeaderRow(const QString &title) | ||||
48 | { | ||||
49 | return QStringLiteral("<tr><th colspan=\"2\">%1</th></tr>").arg(title); | ||||
50 | } | ||||
51 | | ||||
52 | template<typename T> | ||||
53 | static | ||||
54 | QString tableRow(const QString &title, const T &argument) | ||||
55 | { | ||||
56 | return QStringLiteral("<tr><td>%1</td><td>%2</td></tr>").arg(title).arg(argument); | ||||
57 | } | ||||
58 | | ||||
59 | static QString timestampRow(quint32 timestamp) | ||||
60 | { | ||||
61 | return tableRow(i18n("Timestamp"), timestamp); | ||||
62 | } | ||||
63 | | ||||
64 | static QString buttonToString(Qt::MouseButton button) | ||||
65 | { | ||||
66 | switch (button) { | ||||
67 | case Qt::LeftButton: | ||||
68 | return i18nc("A mouse button", "Left"); | ||||
69 | case Qt::RightButton: | ||||
70 | return i18nc("A mouse button", "Right"); | ||||
71 | case Qt::MiddleButton: | ||||
72 | return i18nc("A mouse button", "Middle"); | ||||
73 | case Qt::BackButton: | ||||
74 | return i18nc("A mouse button", "Back"); | ||||
75 | case Qt::ForwardButton: | ||||
76 | return i18nc("A mouse button", "Forward"); | ||||
77 | case Qt::TaskButton: | ||||
78 | return i18nc("A mouse button", "Task"); | ||||
79 | case Qt::ExtraButton4: | ||||
80 | return i18nc("A mouse button", "Extra Button 4"); | ||||
81 | case Qt::ExtraButton5: | ||||
82 | return i18nc("A mouse button", "Extra Button 5"); | ||||
83 | case Qt::ExtraButton6: | ||||
84 | return i18nc("A mouse button", "Extra Button 6"); | ||||
85 | case Qt::ExtraButton7: | ||||
86 | return i18nc("A mouse button", "Extra Button 7"); | ||||
87 | case Qt::ExtraButton8: | ||||
88 | return i18nc("A mouse button", "Extra Button 8"); | ||||
89 | case Qt::ExtraButton9: | ||||
90 | return i18nc("A mouse button", "Extra Button 9"); | ||||
91 | case Qt::ExtraButton10: | ||||
92 | return i18nc("A mouse button", "Extra Button 10"); | ||||
93 | case Qt::ExtraButton11: | ||||
94 | return i18nc("A mouse button", "Extra Button 11"); | ||||
95 | case Qt::ExtraButton12: | ||||
96 | return i18nc("A mouse button", "Extra Button 12"); | ||||
97 | case Qt::ExtraButton13: | ||||
98 | return i18nc("A mouse button", "Extra Button 13"); | ||||
99 | case Qt::ExtraButton14: | ||||
100 | return i18nc("A mouse button", "Extra Button 14"); | ||||
101 | case Qt::ExtraButton15: | ||||
102 | return i18nc("A mouse button", "Extra Button 15"); | ||||
103 | case Qt::ExtraButton16: | ||||
104 | return i18nc("A mouse button", "Extra Button 16"); | ||||
105 | case Qt::ExtraButton17: | ||||
106 | return i18nc("A mouse button", "Extra Button 17"); | ||||
107 | case Qt::ExtraButton18: | ||||
108 | return i18nc("A mouse button", "Extra Button 18"); | ||||
109 | case Qt::ExtraButton19: | ||||
110 | return i18nc("A mouse button", "Extra Button 19"); | ||||
111 | case Qt::ExtraButton20: | ||||
112 | return i18nc("A mouse button", "Extra Button 20"); | ||||
113 | case Qt::ExtraButton21: | ||||
114 | return i18nc("A mouse button", "Extra Button 21"); | ||||
115 | case Qt::ExtraButton22: | ||||
116 | return i18nc("A mouse button", "Extra Button 22"); | ||||
117 | case Qt::ExtraButton23: | ||||
118 | return i18nc("A mouse button", "Extra Button 23"); | ||||
119 | case Qt::ExtraButton24: | ||||
120 | return i18nc("A mouse button", "Extra Button 24"); | ||||
121 | default: | ||||
122 | return QString(); | ||||
123 | } | ||||
124 | } | ||||
125 | | ||||
126 | static QString buttonsToString(Qt::MouseButtons buttons) | ||||
127 | { | ||||
128 | QString ret; | ||||
129 | for (uint i = 1; i < Qt::ExtraButton24; i = i << 1) { | ||||
130 | if (buttons & i) { | ||||
131 | ret.append(buttonToString(Qt::MouseButton(uint(buttons) & i))); | ||||
132 | ret.append(QStringLiteral(" ")); | ||||
133 | } | ||||
134 | }; | ||||
135 | return ret; | ||||
136 | } | ||||
137 | | ||||
138 | static const QString s_hr = QStringLiteral("<hr/>"); | ||||
139 | static const QString s_tableStart = QStringLiteral("<table>"); | ||||
140 | static const QString s_tableEnd = QStringLiteral("</table>"); | ||||
141 | | ||||
142 | DebugConsoleFilter::DebugConsoleFilter(QTextEdit *textEdit) | ||||
143 | : InputEventFilter() | ||||
144 | , m_textEdit(textEdit) | ||||
145 | { | ||||
146 | } | ||||
147 | | ||||
148 | DebugConsoleFilter::~DebugConsoleFilter() = default; | ||||
149 | | ||||
150 | bool DebugConsoleFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton) | ||||
151 | { | ||||
152 | QString text = s_hr; | ||||
153 | const QString timestamp = timestampRow(event->timestamp()); | ||||
154 | | ||||
155 | text.append(s_tableStart); | ||||
156 | switch (event->type()) { | ||||
157 | case QEvent::MouseMove: | ||||
158 | text.append(tableHeaderRow(i18nc("A mouse pointer motion event", "Pointer Motion"))); | ||||
159 | text.append(timestamp); | ||||
160 | text.append(tableRow(i18nc("The global mouse pointer position", "Global Position"), QStringLiteral("%1/%2").arg(event->pos().x()).arg(event->pos().y()))); | ||||
161 | break; | ||||
162 | case QEvent::MouseButtonPress: | ||||
163 | text.append(tableHeaderRow(i18nc("A mouse pointer button press event", "Pointer Button Press"))); | ||||
164 | text.append(timestamp); | ||||
165 | text.append(tableRow(i18nc("A button in a mouse press/release event", "Button"), buttonToString(event->button()))); | ||||
166 | text.append(tableRow(i18nc("A button in a mouse press/release event", "Native Button code"), nativeButton)); | ||||
167 | text.append(tableRow(i18nc("All currently pressed buttons in a mouse press/release event", "Pressed Buttons"), buttonsToString(event->buttons()))); | ||||
168 | break; | ||||
169 | case QEvent::MouseButtonRelease: | ||||
170 | text.append(tableHeaderRow(i18nc("A mouse pointer button release event", "Pointer Button Release"))); | ||||
171 | text.append(timestamp); | ||||
172 | text.append(tableRow(i18nc("A button in a mouse press/release event", "Button"), buttonToString(event->button()))); | ||||
173 | text.append(tableRow(i18nc("A button in a mouse press/release event", "Native Button code"), nativeButton)); | ||||
174 | text.append(tableRow(i18nc("All currently pressed buttons in a mouse press/release event", "Pressed Buttons"), buttonsToString(event->buttons()))); | ||||
175 | break; | ||||
176 | default: | ||||
177 | break; | ||||
178 | } | ||||
179 | text.append(s_tableEnd); | ||||
180 | | ||||
181 | m_textEdit->insertHtml(text); | ||||
182 | m_textEdit->ensureCursorVisible(); | ||||
183 | return false; | ||||
184 | } | ||||
185 | | ||||
186 | bool DebugConsoleFilter::wheelEvent(QWheelEvent *event) | ||||
187 | { | ||||
188 | QString text = s_hr; | ||||
189 | text.append(s_tableStart); | ||||
190 | text.append(tableHeaderRow(i18nc("A mouse pointer axis (wheel) event", "Pointer Axis"))); | ||||
191 | text.append(timestampRow(event->timestamp())); | ||||
192 | const Qt::Orientation orientation = event->angleDelta().x() == 0 ? Qt::Vertical : Qt::Horizontal; | ||||
193 | text.append(tableRow(i18nc("The orientation of a pointer axis event", "Orientation"), | ||||
194 | orientation == Qt::Horizontal ? i18nc("An orientation of a pointer axis event", "Horizontal") | ||||
195 | : i18nc("An orientation of a pointer axis event", "Vertical"))); | ||||
196 | text.append(tableRow(QStringLiteral("Delta"), orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y())); | ||||
197 | text.append(s_tableEnd); | ||||
198 | | ||||
199 | m_textEdit->insertHtml(text); | ||||
200 | m_textEdit->ensureCursorVisible(); | ||||
201 | return false; | ||||
202 | } | ||||
203 | | ||||
204 | bool DebugConsoleFilter::keyEvent(QKeyEvent *event) | ||||
205 | { | ||||
206 | QString text = s_hr; | ||||
207 | text.append(s_tableStart); | ||||
208 | | ||||
209 | switch (event->type()) { | ||||
210 | case QEvent::KeyPress: | ||||
211 | text.append(tableHeaderRow(i18nc("A key press event", "Key Press"))); | ||||
212 | break; | ||||
213 | case QEvent::KeyRelease: | ||||
214 | text.append(tableHeaderRow(i18nc("A key release event", "Key Release"))); | ||||
215 | break; | ||||
216 | default: | ||||
217 | break; | ||||
218 | } | ||||
219 | auto modifiersToString = [event] { | ||||
220 | QString ret; | ||||
221 | if (event->modifiers().testFlag(Qt::ShiftModifier)) { | ||||
222 | ret.append(i18nc("A keyboard modifier", "Shift")); | ||||
223 | ret.append(QStringLiteral(" ")); | ||||
224 | } | ||||
225 | if (event->modifiers().testFlag(Qt::ControlModifier)) { | ||||
226 | ret.append(i18nc("A keyboard modifier", "Control")); | ||||
227 | ret.append(QStringLiteral(" ")); | ||||
228 | } | ||||
229 | if (event->modifiers().testFlag(Qt::AltModifier)) { | ||||
230 | ret.append(i18nc("A keyboard modifier", "Alt")); | ||||
231 | ret.append(QStringLiteral(" ")); | ||||
232 | } | ||||
233 | if (event->modifiers().testFlag(Qt::MetaModifier)) { | ||||
234 | ret.append(i18nc("A keyboard modifier", "Meta")); | ||||
235 | ret.append(QStringLiteral(" ")); | ||||
236 | } | ||||
237 | if (event->modifiers().testFlag(Qt::KeypadModifier)) { | ||||
238 | ret.append(i18nc("A keyboard modifier", "Keypad")); | ||||
239 | ret.append(QStringLiteral(" ")); | ||||
240 | } | ||||
241 | if (event->modifiers().testFlag(Qt::GroupSwitchModifier)) { | ||||
242 | ret.append(i18nc("A keyboard modifier", "Group-switch")); | ||||
243 | ret.append(QStringLiteral(" ")); | ||||
244 | } | ||||
245 | return ret; | ||||
246 | }; | ||||
247 | text.append(timestampRow(event->timestamp())); | ||||
248 | text.append(tableRow(i18nc("Whether the event is an automatic key repeat", "Repeat"), event->isAutoRepeat())); | ||||
249 | text.append(tableRow(i18nc("The code as read from the input device", "Scan code"), event->nativeScanCode())); | ||||
250 | text.append(tableRow(i18nc("The translated code to an Xkb symbol", "Xkb symbol"), event->nativeVirtualKey())); | ||||
251 | text.append(tableRow(i18nc("The translated code interpreted as text", "Utf8"), event->text())); | ||||
252 | text.append(tableRow(i18nc("The currently active modifiers", "Modifiers"), modifiersToString())); | ||||
253 | | ||||
254 | text.append(s_tableEnd); | ||||
255 | | ||||
256 | m_textEdit->insertHtml(text); | ||||
257 | m_textEdit->ensureCursorVisible(); | ||||
258 | return false; | ||||
259 | } | ||||
260 | | ||||
261 | bool DebugConsoleFilter::touchDown(quint32 id, const QPointF &pos, quint32 time) | ||||
262 | { | ||||
263 | QString text = s_hr; | ||||
264 | text.append(s_tableStart); | ||||
265 | text.append(tableHeaderRow(i18nc("A touch down event", "Touch down"))); | ||||
266 | text.append(timestampRow(time)); | ||||
267 | text.append(tableRow(i18nc("The id of the touch point in the touch event", "Point identifier"), id)); | ||||
268 | text.append(tableRow(i18nc("The global position of the touch point", "Global position"), | ||||
269 | QStringLiteral("%1/%2").arg(pos.x()).arg(pos.y()))); | ||||
270 | text.append(s_tableEnd); | ||||
271 | | ||||
272 | m_textEdit->insertHtml(text); | ||||
273 | m_textEdit->ensureCursorVisible(); | ||||
274 | return false; | ||||
275 | } | ||||
276 | | ||||
277 | bool DebugConsoleFilter::touchMotion(quint32 id, const QPointF &pos, quint32 time) | ||||
278 | { | ||||
279 | QString text = s_hr; | ||||
280 | text.append(s_tableStart); | ||||
281 | text.append(tableHeaderRow(i18nc("A touch motion event", "Touch Motion"))); | ||||
282 | text.append(timestampRow(time)); | ||||
283 | text.append(tableRow(i18nc("The id of the touch point in the touch event", "Point identifier"), id)); | ||||
284 | text.append(tableRow(i18nc("The global position of the touch point", "Global position"), | ||||
285 | QStringLiteral("%1/%2").arg(pos.x()).arg(pos.y()))); | ||||
286 | text.append(s_tableEnd); | ||||
287 | | ||||
288 | m_textEdit->insertHtml(text); | ||||
289 | m_textEdit->ensureCursorVisible(); | ||||
290 | return false; | ||||
291 | } | ||||
292 | | ||||
293 | bool DebugConsoleFilter::touchUp(quint32 id, quint32 time) | ||||
294 | { | ||||
295 | QString text = s_hr; | ||||
296 | text.append(s_tableStart); | ||||
297 | text.append(tableHeaderRow(i18nc("A touch up event", "Touch Up"))); | ||||
298 | text.append(timestampRow(time)); | ||||
299 | text.append(tableRow(i18nc("The id of the touch point in the touch event", "Point identifier"), id)); | ||||
300 | text.append(s_tableEnd); | ||||
301 | | ||||
302 | m_textEdit->insertHtml(text); | ||||
303 | m_textEdit->ensureCursorVisible(); | ||||
304 | return false; | ||||
305 | } | ||||
306 | | ||||
45 | DebugConsole::DebugConsole() | 307 | DebugConsole::DebugConsole() | ||
46 | : QWidget() | 308 | : QWidget() | ||
47 | , m_ui(new Ui::DebugConsole) | 309 | , m_ui(new Ui::DebugConsole) | ||
48 | { | 310 | { | ||
49 | m_ui->setupUi(this); | 311 | m_ui->setupUi(this); | ||
50 | m_ui->treeView->setItemDelegate(new DebugConsoleDelegate(this)); | 312 | m_ui->treeView->setItemDelegate(new DebugConsoleDelegate(this)); | ||
51 | m_ui->treeView->setModel(new DebugConsoleModel(this)); | 313 | m_ui->treeView->setModel(new DebugConsoleModel(this)); | ||
52 | m_ui->quitButton->setIcon(QIcon::fromTheme(QStringLiteral("application-exit"))); | 314 | m_ui->quitButton->setIcon(QIcon::fromTheme(QStringLiteral("application-exit"))); | ||
53 | m_ui->windowsButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); | 315 | m_ui->windowsButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); | ||
54 | m_ui->surfacesButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); | 316 | m_ui->surfacesButton->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); | ||
55 | 317 | | |||
56 | if (kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) { | 318 | if (kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) { | ||
57 | m_ui->surfacesButton->setDisabled(true); | 319 | m_ui->surfacesButton->setDisabled(true); | ||
320 | m_ui->inputEventsButton->setDisabled(true); | ||||
58 | } | 321 | } | ||
59 | 322 | | |||
60 | connect(m_ui->quitButton, &QAbstractButton::clicked, this, &DebugConsole::deleteLater); | 323 | connect(m_ui->quitButton, &QAbstractButton::clicked, this, &DebugConsole::deleteLater); | ||
61 | connect(m_ui->windowsButton, &QAbstractButton::toggled, this, | 324 | connect(m_ui->windowsButton, &QAbstractButton::toggled, this, | ||
62 | [this] (bool toggled) { | 325 | [this] (bool toggled) { | ||
63 | if (!toggled) { | 326 | if (!toggled) { | ||
64 | return; | 327 | return; | ||
65 | } | 328 | } | ||
66 | m_ui->surfacesButton->setChecked(false); | 329 | m_ui->surfacesButton->setChecked(false); | ||
330 | m_ui->inputEventsButton->setChecked(false); | ||||
67 | m_ui->treeView->model()->deleteLater(); | 331 | m_ui->treeView->model()->deleteLater(); | ||
68 | m_ui->treeView->setModel(new DebugConsoleModel(this)); | 332 | m_ui->treeView->setModel(new DebugConsoleModel(this)); | ||
333 | m_ui->treeView->setVisible(true); | ||||
334 | m_ui->inputTextEdit->setVisible(false); | ||||
69 | } | 335 | } | ||
70 | ); | 336 | ); | ||
71 | connect(m_ui->surfacesButton, &QAbstractButton::toggled, this, | 337 | connect(m_ui->surfacesButton, &QAbstractButton::toggled, this, | ||
72 | [this] (bool toggled) { | 338 | [this] (bool toggled) { | ||
73 | if (!toggled) { | 339 | if (!toggled) { | ||
74 | return; | 340 | return; | ||
75 | } | 341 | } | ||
76 | m_ui->windowsButton->setChecked(false); | 342 | m_ui->windowsButton->setChecked(false); | ||
343 | m_ui->inputEventsButton->setChecked(false); | ||||
77 | m_ui->treeView->model()->deleteLater(); | 344 | m_ui->treeView->model()->deleteLater(); | ||
78 | m_ui->treeView->setModel(new SurfaceTreeModel(this)); | 345 | m_ui->treeView->setModel(new SurfaceTreeModel(this)); | ||
346 | m_ui->treeView->setVisible(true); | ||||
347 | m_ui->inputTextEdit->setVisible(false); | ||||
79 | } | 348 | } | ||
80 | ); | 349 | ); | ||
350 | connect(m_ui->inputEventsButton, &QAbstractButton::toggled, this, | ||||
351 | [this] (bool toggled) { | ||||
352 | if (!toggled) { | ||||
353 | return; | ||||
354 | } | ||||
355 | m_ui->windowsButton->setChecked(false); | ||||
356 | m_ui->surfacesButton->setChecked(false); | ||||
357 | m_ui->treeView->setVisible(false); | ||||
358 | m_ui->inputTextEdit->setVisible(true); | ||||
359 | if (m_inputFilter.isNull()) { | ||||
360 | m_inputFilter.reset(new DebugConsoleFilter(m_ui->inputTextEdit)); | ||||
361 | input()->prepandInputEventFilter(m_inputFilter.data()); | ||||
362 | } | ||||
363 | } | ||||
364 | ); | ||||
365 | | ||||
366 | m_ui->inputTextEdit->setVisible(false); | ||||
81 | 367 | | |||
82 | // for X11 | 368 | // for X11 | ||
83 | setWindowFlags(Qt::X11BypassWindowManagerHint); | 369 | setWindowFlags(Qt::X11BypassWindowManagerHint); | ||
84 | } | 370 | } | ||
85 | 371 | | |||
86 | DebugConsole::~DebugConsole() = default; | 372 | DebugConsole::~DebugConsole() = default; | ||
87 | 373 | | |||
88 | DebugConsoleDelegate::DebugConsoleDelegate(QObject *parent) | 374 | DebugConsoleDelegate::DebugConsoleDelegate(QObject *parent) | ||
▲ Show 20 Lines • Show All 655 Lines • Show Last 20 Lines |