KWin
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
connection.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "connection.h"
10#include "context.h"
11#include "device.h"
12#include "events.h"
13
14// TODO: Make it compile also in testing environment
15#ifndef KWIN_BUILD_TESTING
16#include "core/output.h"
17#include "core/outputbackend.h"
18#include "main.h"
19#include "window.h"
20#include "workspace.h"
21#endif
22
23#include "core/session.h"
24#include "input_event.h"
25#include "libinput_logging.h"
26#include "utils/realtime.h"
27#include "utils/udev.h"
28
29#include <QDBusConnection>
30#include <QMutexLocker>
31#include <QSocketNotifier>
32
33#include <cmath>
34#include <libinput.h>
35
36namespace KWin
37{
38namespace LibInput
39{
40
41class ConnectionAdaptor : public QObject
42{
43 Q_OBJECT
44 Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.InputDeviceManager")
45 Q_PROPERTY(QStringList devicesSysNames READ devicesSysNames CONSTANT)
46
48 Connection *m_con;
49
50public:
52 : QObject(con)
53 , m_con(con)
54 {
55 connect(con, &Connection::deviceAdded, this, [this](LibInput::Device *inputDevice) {
56 Q_EMIT deviceAdded(inputDevice->sysName());
57 });
58 connect(con, &Connection::deviceRemoved, this, [this](LibInput::Device *inputDevice) {
59 Q_EMIT deviceRemoved(inputDevice->sysName());
60 });
61
62 QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/InputDevice"),
63 QStringLiteral("org.kde.KWin.InputDeviceManager"),
64 this,
65 QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals);
66 }
67
69 {
70 QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/KWin/InputDeviceManager"));
71 }
72
73 QStringList devicesSysNames()
74 {
75 return m_con->devicesSysNames();
76 }
77
78Q_SIGNALS:
79 void deviceAdded(QString sysName);
80 void deviceRemoved(QString sysName);
81};
82
83std::unique_ptr<Connection> Connection::create(Session *session)
84{
85 std::unique_ptr<Udev> udev = std::make_unique<Udev>();
86 if (!udev->isValid()) {
87 qCWarning(KWIN_LIBINPUT) << "Failed to initialize udev";
88 return nullptr;
89 }
90 std::unique_ptr<Context> context = std::make_unique<Context>(session, std::move(udev));
91 if (!context->isValid()) {
92 qCWarning(KWIN_LIBINPUT) << "Failed to create context from udev";
93 return nullptr;
94 }
95 if (!context->initialize()) {
96 qCWarning(KWIN_LIBINPUT) << "Failed to initialize context";
97 return nullptr;
98 }
99 return std::unique_ptr<Connection>(new Connection(std::move(context)));
100}
101
102Connection::Connection(std::unique_ptr<Context> &&input)
103 : m_notifier(nullptr)
104 , m_connectionAdaptor(std::make_unique<ConnectionAdaptor>(this))
105 , m_input(std::move(input))
106{
107 Q_ASSERT(m_input);
108 // need to connect to KGlobalSettings as the mouse KCM does not emit a dedicated signal
109 QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"),
110 QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int, int)));
111}
112
113Connection::~Connection() = default;
114
116{
117 QMetaObject::invokeMethod(this, &Connection::doSetup, Qt::QueuedConnection);
118}
119
120void Connection::doSetup()
121{
122 Q_ASSERT(!m_notifier);
123
124 gainRealTime();
125
126 m_notifier = std::make_unique<QSocketNotifier>(m_input->fileDescriptor(), QSocketNotifier::Read);
127 connect(m_notifier.get(), &QSocketNotifier::activated, this, &Connection::handleEvent);
128
129 connect(m_input->session(), &Session::activeChanged, this, [this](bool active) {
130 if (active) {
131 if (!m_input->isSuspended()) {
132 return;
133 }
134 m_input->resume();
135 } else {
136 deactivate();
137 }
138 });
139 handleEvent();
140}
141
142void Connection::deactivate()
143{
144 if (m_input->isSuspended()) {
145 return;
146 }
147 m_input->suspend();
148 handleEvent();
149}
150
151void Connection::handleEvent()
152{
153 QMutexLocker locker(&m_mutex);
154 const bool wasEmpty = m_eventQueue.empty();
155 do {
156 m_input->dispatch();
157 std::unique_ptr<Event> event = m_input->event();
158 if (!event) {
159 break;
160 }
161 m_eventQueue.push_back(std::move(event));
162 } while (true);
163 if (wasEmpty && !m_eventQueue.empty()) {
164 Q_EMIT eventsRead();
165 }
166}
167
168#ifndef KWIN_BUILD_TESTING
169QPointF devicePointToGlobalPosition(const QPointF &devicePos, const Output *output)
170{
171 QPointF pos = devicePos;
172 // TODO: Do we need to handle the flipped cases differently?
173 switch (output->transform().kind()) {
176 break;
179 pos = QPointF(output->modeSize().height() - devicePos.y(), devicePos.x());
180 break;
183 pos = QPointF(output->modeSize().width() - devicePos.x(),
184 output->modeSize().height() - devicePos.y());
185 break;
188 pos = QPointF(devicePos.y(), output->modeSize().width() - devicePos.x());
189 break;
190 default:
191 Q_UNREACHABLE();
192 }
193 return output->geometry().topLeft() + pos / output->scale();
194}
195#endif
196
197KWin::TabletToolId createTabletId(libinput_tablet_tool *tool, Device *dev)
198{
199 auto serial = libinput_tablet_tool_get_serial(tool);
200 auto toolId = libinput_tablet_tool_get_tool_id(tool);
201 auto type = libinput_tablet_tool_get_type(tool);
203 switch (type) {
204 case LIBINPUT_TABLET_TOOL_TYPE_PEN:
205 toolType = InputRedirection::Pen;
206 break;
207 case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
208 toolType = InputRedirection::Eraser;
209 break;
210 case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
211 toolType = InputRedirection::Brush;
212 break;
213 case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
214 toolType = InputRedirection::Pencil;
215 break;
216 case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
218 break;
219 case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
220 toolType = InputRedirection::Mouse;
221 break;
222 case LIBINPUT_TABLET_TOOL_TYPE_LENS:
223 toolType = InputRedirection::Lens;
224 break;
225 case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
226 toolType = InputRedirection::Totem;
227 break;
228 }
229 QList<InputRedirection::Capability> capabilities;
230 if (libinput_tablet_tool_has_pressure(tool)) {
231 capabilities << InputRedirection::Pressure;
232 }
233 if (libinput_tablet_tool_has_distance(tool)) {
234 capabilities << InputRedirection::Distance;
235 }
236 if (libinput_tablet_tool_has_rotation(tool)) {
237 capabilities << InputRedirection::Rotation;
238 }
239 if (libinput_tablet_tool_has_tilt(tool)) {
240 capabilities << InputRedirection::Tilt;
241 }
242 if (libinput_tablet_tool_has_slider(tool)) {
243 capabilities << InputRedirection::Slider;
244 }
245 if (libinput_tablet_tool_has_wheel(tool)) {
246 capabilities << InputRedirection::Wheel;
247 }
248 return {dev->sysName(), toolType, capabilities, serial, toolId, dev->groupUserData(), dev->name()};
249}
250
251static TabletPadId createTabletPadId(LibInput::Device *device)
252{
253 if (!device || !device->groupUserData()) {
254 return {};
255 }
256
257 return {
258 device->name(),
259 device->groupUserData(),
260 };
261}
262
263void Connection::processEvents()
264{
265 QMutexLocker locker(&m_mutex);
266 while (m_eventQueue.size() != 0) {
267 std::unique_ptr<Event> event = std::move(m_eventQueue.front());
268 m_eventQueue.pop_front();
269 switch (event->type()) {
270 case LIBINPUT_EVENT_DEVICE_ADDED: {
271 auto device = new Device(event->nativeDevice());
272 device->moveToThread(thread());
273 m_devices << device;
274
275 applyDeviceConfig(device);
276 applyScreenToDevice(device);
277
278 connect(device, &Device::outputNameChanged, this, [this, device] {
279 // If the output name changes from something to empty we need to
280 // re-run the assignment heuristic so that an output is assinged
281 if (device->outputName().isEmpty()) {
282 applyScreenToDevice(device);
283 }
284 });
285
286 Q_EMIT deviceAdded(device);
287 break;
288 }
289 case LIBINPUT_EVENT_DEVICE_REMOVED: {
290 auto it = std::find_if(m_devices.begin(), m_devices.end(), [&event](Device *d) {
291 return event->device() == d;
292 });
293 if (it == m_devices.end()) {
294 // we don't know this device
295 break;
296 }
297 auto device = *it;
298 m_devices.erase(it);
299 Q_EMIT deviceRemoved(device);
300 device->deleteLater();
301 break;
302 }
303 case LIBINPUT_EVENT_KEYBOARD_KEY: {
304 KeyEvent *ke = static_cast<KeyEvent *>(event.get());
305 Q_EMIT ke->device()->keyChanged(ke->key(), ke->state(), ke->time(), ke->device());
306 break;
307 }
308 case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL: {
309 const PointerEvent *pointerEvent = static_cast<PointerEvent *>(event.get());
310 const auto axes = pointerEvent->axis();
311 for (const InputRedirection::PointerAxis &axis : axes) {
312 Q_EMIT pointerEvent->device()->pointerAxisChanged(axis,
313 pointerEvent->scrollValue(axis),
314 pointerEvent->scrollValueV120(axis),
316 pointerEvent->time(),
317 pointerEvent->device());
318 }
319 Q_EMIT pointerEvent->device()->pointerFrame(pointerEvent->device());
320 break;
321 }
322 case LIBINPUT_EVENT_POINTER_SCROLL_FINGER: {
323 const PointerEvent *pointerEvent = static_cast<PointerEvent *>(event.get());
324 const auto axes = pointerEvent->axis();
325 for (const InputRedirection::PointerAxis &axis : axes) {
326 Q_EMIT pointerEvent->device()->pointerAxisChanged(axis,
327 pointerEvent->scrollValue(axis),
328 0,
330 pointerEvent->time(),
331 pointerEvent->device());
332 }
333 Q_EMIT pointerEvent->device()->pointerFrame(pointerEvent->device());
334 break;
335 }
336 case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS: {
337 const PointerEvent *pointerEvent = static_cast<PointerEvent *>(event.get());
338 const auto axes = pointerEvent->axis();
339 for (const InputRedirection::PointerAxis &axis : axes) {
340 Q_EMIT pointerEvent->device()->pointerAxisChanged(axis,
341 pointerEvent->scrollValue(axis),
342 0,
344 pointerEvent->time(),
345 pointerEvent->device());
346 }
347 Q_EMIT pointerEvent->device()->pointerFrame(pointerEvent->device());
348 break;
349 }
350 case LIBINPUT_EVENT_POINTER_BUTTON: {
351 PointerEvent *pe = static_cast<PointerEvent *>(event.get());
352 Q_EMIT pe->device()->pointerButtonChanged(pe->button(), pe->buttonState(), pe->time(), pe->device());
353 Q_EMIT pe->device()->pointerFrame(pe->device());
354 break;
355 }
356 case LIBINPUT_EVENT_POINTER_MOTION: {
357 PointerEvent *pe = static_cast<PointerEvent *>(event.get());
358 auto delta = pe->delta();
359 auto deltaNonAccel = pe->deltaUnaccelerated();
360 auto latestTime = pe->time();
361 auto it = m_eventQueue.begin();
362 while (it != m_eventQueue.end()) {
363 if ((*it)->type() == LIBINPUT_EVENT_POINTER_MOTION) {
364 std::unique_ptr<PointerEvent> p{static_cast<PointerEvent *>(it->release())};
365 delta += p->delta();
366 deltaNonAccel += p->deltaUnaccelerated();
367 latestTime = p->time();
368 it = m_eventQueue.erase(it);
369 } else {
370 break;
371 }
372 }
373 Q_EMIT pe->device()->pointerMotion(delta, deltaNonAccel, latestTime, pe->device());
374 Q_EMIT pe->device()->pointerFrame(pe->device());
375 break;
376 }
377 case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: {
378 PointerEvent *pe = static_cast<PointerEvent *>(event.get());
379 if (workspace()) {
380 Q_EMIT pe->device()->pointerMotionAbsolute(pe->absolutePos(workspace()->geometry().size()), pe->time(), pe->device());
381 Q_EMIT pe->device()->pointerFrame(pe->device());
382 }
383 break;
384 }
385 case LIBINPUT_EVENT_TOUCH_DOWN: {
386#ifndef KWIN_BUILD_TESTING
387 TouchEvent *te = static_cast<TouchEvent *>(event.get());
388 const auto *output = te->device()->output();
389 if (!output) {
390 qCWarning(KWIN_LIBINPUT) << "Touch down received for device with no output assigned";
391 break;
392 }
393 const QPointF globalPos = devicePointToGlobalPosition(te->absolutePos(output->modeSize()), output);
394 Q_EMIT te->device()->touchDown(te->id(), globalPos, te->time(), te->device());
395 break;
396#endif
397 }
398 case LIBINPUT_EVENT_TOUCH_UP: {
399 TouchEvent *te = static_cast<TouchEvent *>(event.get());
400 const auto *output = te->device()->output();
401 if (!output) {
402 break;
403 }
404 Q_EMIT te->device()->touchUp(te->id(), te->time(), te->device());
405 break;
406 }
407 case LIBINPUT_EVENT_TOUCH_MOTION: {
408#ifndef KWIN_BUILD_TESTING
409 TouchEvent *te = static_cast<TouchEvent *>(event.get());
410 const auto *output = te->device()->output();
411 if (!output) {
412 break;
413 }
414 const QPointF globalPos = devicePointToGlobalPosition(te->absolutePos(output->modeSize()), output);
415 Q_EMIT te->device()->touchMotion(te->id(), globalPos, te->time(), te->device());
416 break;
417#endif
418 }
419 case LIBINPUT_EVENT_TOUCH_CANCEL: {
420 Q_EMIT event->device()->touchCanceled(event->device());
421 break;
422 }
423 case LIBINPUT_EVENT_TOUCH_FRAME: {
424 Q_EMIT event->device()->touchFrame(event->device());
425 break;
426 }
427 case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: {
428 PinchGestureEvent *pe = static_cast<PinchGestureEvent *>(event.get());
429 Q_EMIT pe->device()->pinchGestureBegin(pe->fingerCount(), pe->time(), pe->device());
430 break;
431 }
432 case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: {
433 PinchGestureEvent *pe = static_cast<PinchGestureEvent *>(event.get());
434 Q_EMIT pe->device()->pinchGestureUpdate(pe->scale(), pe->angleDelta(), pe->delta(), pe->time(), pe->device());
435 break;
436 }
437 case LIBINPUT_EVENT_GESTURE_PINCH_END: {
438 PinchGestureEvent *pe = static_cast<PinchGestureEvent *>(event.get());
439 if (pe->isCancelled()) {
440 Q_EMIT pe->device()->pinchGestureCancelled(pe->time(), pe->device());
441 } else {
442 Q_EMIT pe->device()->pinchGestureEnd(pe->time(), pe->device());
443 }
444 break;
445 }
446 case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: {
447 SwipeGestureEvent *se = static_cast<SwipeGestureEvent *>(event.get());
448 Q_EMIT se->device()->swipeGestureBegin(se->fingerCount(), se->time(), se->device());
449 break;
450 }
451 case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: {
452 SwipeGestureEvent *se = static_cast<SwipeGestureEvent *>(event.get());
453 Q_EMIT se->device()->swipeGestureUpdate(se->delta(), se->time(), se->device());
454 break;
455 }
456 case LIBINPUT_EVENT_GESTURE_SWIPE_END: {
457 SwipeGestureEvent *se = static_cast<SwipeGestureEvent *>(event.get());
458 if (se->isCancelled()) {
459 Q_EMIT se->device()->swipeGestureCancelled(se->time(), se->device());
460 } else {
461 Q_EMIT se->device()->swipeGestureEnd(se->time(), se->device());
462 }
463 break;
464 }
465 case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN: {
466 HoldGestureEvent *he = static_cast<HoldGestureEvent *>(event.get());
467 Q_EMIT he->device()->holdGestureBegin(he->fingerCount(), he->time(), he->device());
468 break;
469 }
470 case LIBINPUT_EVENT_GESTURE_HOLD_END: {
471 HoldGestureEvent *he = static_cast<HoldGestureEvent *>(event.get());
472 if (he->isCancelled()) {
473 Q_EMIT he->device()->holdGestureCancelled(he->time(), he->device());
474 } else {
475 Q_EMIT he->device()->holdGestureEnd(he->time(), he->device());
476 }
477 break;
478 }
479 case LIBINPUT_EVENT_SWITCH_TOGGLE: {
480 SwitchEvent *se = static_cast<SwitchEvent *>(event.get());
481 switch (se->state()) {
483 Q_EMIT se->device()->switchToggledOff(se->time(), se->device());
484 break;
486 Q_EMIT se->device()->switchToggledOn(se->time(), se->device());
487 break;
488 default:
489 Q_UNREACHABLE();
490 }
491 break;
492 }
493 case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
494 case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
495 case LIBINPUT_EVENT_TABLET_TOOL_TIP: {
496 auto *tte = static_cast<TabletToolEvent *>(event.get());
497
499 switch (event->type()) {
500 case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
501 tabletEventType = KWin::InputRedirection::Axis;
502 break;
503 case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
504 tabletEventType = KWin::InputRedirection::Proximity;
505 break;
506 case LIBINPUT_EVENT_TABLET_TOOL_TIP:
507 default:
508 tabletEventType = KWin::InputRedirection::Tip;
509 break;
510 }
511
512 if (workspace()) {
513#ifndef KWIN_BUILD_TESTING
514 QPointF globalPos;
515 if (tte->device()->isMapToWorkspace()) {
516 globalPos = workspace()->geometry().topLeft() + tte->transformedPosition(workspace()->geometry().size());
517 } else {
518 Output *output = tte->device()->output();
519 if (!output && workspace()->activeWindow()) {
520 output = workspace()->activeWindow()->output();
521 }
522 if (!output) {
523 output = workspace()->activeOutput();
524 }
525 globalPos = devicePointToGlobalPosition(tte->transformedPosition(output->modeSize()), output);
526 }
527#else
528 const QPointF globalPos;
529#endif
530 Q_EMIT event->device()->tabletToolEvent(tabletEventType,
531 globalPos, tte->pressure(),
532 tte->xTilt(), tte->yTilt(), tte->rotation(),
533 tte->isTipDown(), tte->isNearby(), createTabletId(tte->tool(), event->device()), tte->time());
534 }
535 break;
536 }
537 case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: {
538 auto *tabletEvent = static_cast<TabletToolButtonEvent *>(event.get());
539 Q_EMIT event->device()->tabletToolButtonEvent(tabletEvent->buttonId(),
540 tabletEvent->isButtonPressed(),
541 createTabletId(tabletEvent->tool(), event->device()), tabletEvent->time());
542 break;
543 }
544 case LIBINPUT_EVENT_TABLET_PAD_BUTTON: {
545 auto *tabletEvent = static_cast<TabletPadButtonEvent *>(event.get());
546 Q_EMIT event->device()->tabletPadButtonEvent(tabletEvent->buttonId(),
547 tabletEvent->isButtonPressed(),
548 createTabletPadId(event->device()), tabletEvent->time());
549 break;
550 }
551 case LIBINPUT_EVENT_TABLET_PAD_RING: {
552 auto *tabletEvent = static_cast<TabletPadRingEvent *>(event.get());
553 tabletEvent->position();
554 Q_EMIT event->device()->tabletPadRingEvent(tabletEvent->number(),
555 tabletEvent->position(),
556 tabletEvent->source() == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
557 createTabletPadId(event->device()), tabletEvent->time());
558 break;
559 }
560 case LIBINPUT_EVENT_TABLET_PAD_STRIP: {
561 auto *tabletEvent = static_cast<TabletPadStripEvent *>(event.get());
562 Q_EMIT event->device()->tabletPadStripEvent(tabletEvent->number(),
563 tabletEvent->position(),
564 tabletEvent->source() == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
565 createTabletPadId(event->device()), tabletEvent->time());
566 break;
567 }
568 default:
569 // nothing
570 break;
571 }
572 }
573}
574
575void Connection::updateScreens()
576{
577 QMutexLocker locker(&m_mutex);
578 for (auto device : std::as_const(m_devices)) {
579 applyScreenToDevice(device);
580 }
581}
582
583void Connection::applyScreenToDevice(Device *device)
584{
585#ifndef KWIN_BUILD_TESTING
586 QMutexLocker locker(&m_mutex);
587 if (!device->isTouch() && !device->isTabletTool()) {
588 return;
589 }
590
591 Output *deviceOutput = nullptr;
592 const QList<Output *> outputs = kwinApp()->outputBackend()->outputs();
593
594 // let's try to find a screen for it
595 if (!device->outputName().isEmpty()) {
596 // we have an output name, try to find a screen with matching name
597 for (Output *output : outputs) {
598 if (!output->isEnabled()) {
599 continue;
600 }
601 if (output->name() == device->outputName()) {
602 deviceOutput = output;
603 break;
604 }
605 }
606 }
607 if (!deviceOutput && device->isTouch()) {
608 // do we have an internal screen?
609 Output *internalOutput = nullptr;
610 for (Output *output : outputs) {
611 if (!output->isEnabled()) {
612 continue;
613 }
614 if (output->isInternal()) {
615 internalOutput = output;
616 break;
617 }
618 }
619 auto testScreenMatches = [device](const Output *output) {
620 const auto &size = device->size();
621 const auto &screenSize = output->physicalSize();
622 return std::round(size.width()) == std::round(screenSize.width())
623 && std::round(size.height()) == std::round(screenSize.height());
624 };
625 if (internalOutput && testScreenMatches(internalOutput)) {
626 deviceOutput = internalOutput;
627 }
628 // let's compare all screens for size
629 for (Output *output : outputs) {
630 if (!output->isEnabled()) {
631 continue;
632 }
633 if (testScreenMatches(output)) {
634 deviceOutput = output;
635 break;
636 }
637 }
638 if (!deviceOutput) {
639 // still not found
640 if (internalOutput) {
641 // we have an internal id, so let's use that
642 deviceOutput = internalOutput;
643 } else {
644 for (Output *output : outputs) {
645 // just take first screen, we have no clue
646 if (output->isEnabled()) {
647 deviceOutput = output;
648 break;
649 }
650 }
651 }
652 }
653 }
654
655 device->setOutput(deviceOutput);
656
657 // TODO: this is currently non-functional even on DRM. Needs orientation() override there.
658 device->setOrientation(Qt::PrimaryOrientation);
659#endif
660}
661
662void Connection::applyDeviceConfig(Device *device)
663{
664 KConfigGroup defaults = m_config->group(QStringLiteral("Libinput")).group(QStringLiteral("Defaults"));
665 if (defaults.isValid()) {
666 if (device->isAlphaNumericKeyboard() && defaults.hasGroup(QStringLiteral("Keyboard"))) {
667 defaults = defaults.group(QStringLiteral("Keyboard"));
668 } else if (device->isTouchpad() && defaults.hasGroup(QStringLiteral("Touchpad"))) {
669 // A Touchpad is a Pointer, so we need to check for it before Pointer.
670 defaults = defaults.group(QStringLiteral("Touchpad"));
671 } else if (device->isPointer() && defaults.hasGroup(QStringLiteral("Pointer"))) {
672 defaults = defaults.group(QStringLiteral("Pointer"));
673 }
674
675 device->setDefaultConfig(defaults);
676 }
677
678 // pass configuration to Device
679 device->setConfig(m_config->group(QStringLiteral("Libinput")).group(QString::number(device->vendor())).group(QString::number(device->product())).group(device->name()));
680 device->loadConfiguration();
681}
682
683void Connection::slotKGlobalSettingsNotifyChange(int type, int arg)
684{
685 if (type == 3 && arg == 0 ) {
686 m_config->reparseConfiguration();
687 for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) {
688 if ((*it)->isPointer()) {
689 applyDeviceConfig(*it);
690 }
691 }
692 }
693}
694
695QStringList Connection::devicesSysNames() const
696{
697 QStringList sl;
698 for (Device *d : std::as_const(m_devices)) {
699 sl.append(d->sysName());
700 }
701 return sl;
702}
703
704}
705}
706
707#include "connection.moc"
708
709#include "moc_connection.cpp"
void tabletPadButtonEvent(uint button, bool isPressed, const TabletPadId &tabletPadId, std::chrono::microseconds time)
void touchMotion(qint32 id, const QPointF &absolutePos, std::chrono::microseconds time, InputDevice *device)
void swipeGestureUpdate(const QPointF &delta, std::chrono::microseconds time, InputDevice *device)
void pointerMotion(const QPointF &delta, const QPointF &deltaNonAccelerated, std::chrono::microseconds time, InputDevice *device)
void pointerFrame(InputDevice *device)
void swipeGestureCancelled(std::chrono::microseconds time, InputDevice *device)
void switchToggledOn(std::chrono::microseconds time, InputDevice *device)
void holdGestureBegin(int fingerCount, std::chrono::microseconds time, InputDevice *device)
void pinchGestureBegin(int fingerCount, std::chrono::microseconds time, InputDevice *device)
void pointerButtonChanged(quint32 button, InputRedirection::PointerButtonState state, std::chrono::microseconds time, InputDevice *device)
void pinchGestureCancelled(std::chrono::microseconds time, InputDevice *device)
void holdGestureCancelled(std::chrono::microseconds time, InputDevice *device)
void switchToggledOff(std::chrono::microseconds time, InputDevice *device)
void pinchGestureUpdate(qreal scale, qreal angleDelta, const QPointF &delta, std::chrono::microseconds time, InputDevice *device)
void touchDown(qint32 id, const QPointF &absolutePos, std::chrono::microseconds time, InputDevice *device)
void tabletPadStripEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time)
void tabletToolButtonEvent(uint button, bool isPressed, const TabletToolId &tabletToolId, std::chrono::microseconds time)
void pointerMotionAbsolute(const QPointF &position, std::chrono::microseconds time, InputDevice *device)
void holdGestureEnd(std::chrono::microseconds time, InputDevice *device)
void swipeGestureEnd(std::chrono::microseconds time, InputDevice *device)
void swipeGestureBegin(int fingerCount, std::chrono::microseconds time, InputDevice *device)
void keyChanged(quint32 key, InputRedirection::KeyboardKeyState, std::chrono::microseconds time, InputDevice *device)
void pinchGestureEnd(std::chrono::microseconds time, InputDevice *device)
void touchUp(qint32 id, std::chrono::microseconds time, InputDevice *device)
void pointerAxisChanged(InputRedirection::PointerAxis axis, qreal delta, qint32 deltaV120, InputRedirection::PointerAxisSource source, std::chrono::microseconds time, InputDevice *device)
void deviceRemoved(QString sysName)
void deviceAdded(QString sysName)
QStringList devicesSysNames() const
void deviceAdded(KWin::LibInput::Device *)
void deviceRemoved(KWin::LibInput::Device *)
static std::unique_ptr< Connection > create(Session *session)
bool isTabletTool() const override
Definition device.h:179
void * groupUserData() const
Definition device.cpp:538
void setOrientation(Qt::ScreenOrientation orientation)
Definition device.cpp:617
Output * output() const
Definition device.cpp:655
void setOutput(Output *output)
Definition device.cpp:660
bool isTouch() const override
Definition device.h:175
Device * device() const
Definition events.cpp:85
std::chrono::microseconds time() const
Definition events.cpp:259
uint32_t key() const
Definition events.cpp:109
InputRedirection::KeyboardKeyState state() const
Definition events.cpp:114
std::chrono::microseconds time() const
Definition events.cpp:126
std::chrono::microseconds time() const
Definition events.cpp:165
QPointF absolutePos() const
Definition events.cpp:139
qint32 scrollValueV120(InputRedirection::PointerAxis axis) const
Definition events.cpp:209
InputRedirection::PointerButtonState buttonState() const
Definition events.cpp:176
QPointF deltaUnaccelerated() const
Definition events.cpp:159
QList< InputRedirection::PointerAxis > axis() const
Definition events.cpp:189
uint32_t button() const
Definition events.cpp:170
qreal scrollValue(InputRedirection::PointerAxis a) const
Definition events.cpp:201
std::chrono::microseconds time() const
Definition events.cpp:332
std::chrono::microseconds time() const
Definition events.cpp:225
QPointF absolutePos() const
Definition events.cpp:230
qreal scale() const
Definition output.cpp:455
QSize modeSize() const
Definition output.cpp:480
OutputTransform transform() const
Definition output.cpp:369
QRect geometry
Definition output.h:134
Kind kind() const
Definition output.cpp:64
void activeChanged(bool active)
KWin::Output * output
Definition window.h:111
Window * activeWindow() const
Definition workspace.h:767
Output * activeOutput() const
QRect geometry() const
KWin::TabletToolId createTabletId(libinput_tablet_tool *tool, Device *dev)
QPointF devicePointToGlobalPosition(const QPointF &devicePos, const Output *output)
QList< KWayland::Client::Output * > outputs
Session::Type type
Definition session.cpp:17
void gainRealTime()
Definition realtime.cpp:16
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549
#define private