Make it possible to autodetect the tablet mode
Summary: At the moment it's broken for many of the laptops I've seen, this opens the possibility to start toying with them. The right fix would be to get the kernel to emit the right signals but I'm afraid for some hardware it will be close to impossible. This includes a kconfig variable variable that will detect it as follows: if there's a touchscreen, when the touchpad gets removed we are on tablet mode (i.e. the pointing will be done using the finger), when it's connected back tablet mode will be restored. Reviewers: #kwin, #plasma, davidedmundson Reviewed By: #kwin, #plasma, davidedmundson Subscribers: mart, davidedmundson, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D19604
This commit is contained in:
parent
e7d3099ddd
commit
4020056532
4 changed files with 99 additions and 30 deletions
|
@ -43,7 +43,7 @@ class Event;
|
|||
class Device;
|
||||
class Context;
|
||||
|
||||
class Connection : public QObject
|
||||
class KWIN_EXPORT Connection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QMatrix4x4>
|
||||
#include <QSizeF>
|
||||
#include <QVector>
|
||||
#include "kwin_export.h"
|
||||
|
||||
struct libinput_device;
|
||||
|
||||
|
@ -37,7 +38,7 @@ namespace LibInput
|
|||
{
|
||||
enum class ConfigKey;
|
||||
|
||||
class Device : public QObject
|
||||
class KWIN_EXPORT Device : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.InputDevice")
|
||||
|
|
|
@ -25,53 +25,92 @@
|
|||
#include "input_event_spy.h"
|
||||
|
||||
#include "libinput/device.h"
|
||||
#include "libinput/connection.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDBusConnection>
|
||||
|
||||
using namespace KWin;
|
||||
|
||||
KWIN_SINGLETON_FACTORY_VARIABLE(TabletModeManager, s_manager)
|
||||
|
||||
class KWin::TabletModeInputEventSpy : public InputEventSpy
|
||||
class TabletModeSwitchEventSpy : public QObject, public InputEventSpy
|
||||
{
|
||||
public:
|
||||
explicit TabletModeInputEventSpy(TabletModeManager *parent);
|
||||
explicit TabletModeSwitchEventSpy(TabletModeManager *parent)
|
||||
: QObject(parent)
|
||||
, m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void switchEvent(SwitchEvent *event) override
|
||||
{
|
||||
if (!event->device()->isTabletModeSwitch()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->state()) {
|
||||
case SwitchEvent::State::Off:
|
||||
m_parent->setIsTablet(false);
|
||||
break;
|
||||
case SwitchEvent::State::On:
|
||||
m_parent->setIsTablet(true);
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void switchEvent(SwitchEvent *event) override;
|
||||
private:
|
||||
TabletModeManager *m_parent;
|
||||
TabletModeManager * const m_parent;
|
||||
};
|
||||
|
||||
TabletModeInputEventSpy::TabletModeInputEventSpy(TabletModeManager *parent)
|
||||
: m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void TabletModeInputEventSpy::switchEvent(SwitchEvent *event)
|
||||
class TabletModeTouchpadRemovedSpy : public QObject
|
||||
{
|
||||
if (!event->device()->isTabletModeSwitch()) {
|
||||
return;
|
||||
public:
|
||||
explicit TabletModeTouchpadRemovedSpy(TabletModeManager *parent)
|
||||
: QObject(parent)
|
||||
, m_parent(parent)
|
||||
{
|
||||
auto c = LibInput::Connection::self();
|
||||
connect(c, &LibInput::Connection::deviceAdded, this, &TabletModeTouchpadRemovedSpy::refresh);
|
||||
connect(c, &LibInput::Connection::deviceRemoved, this, &TabletModeTouchpadRemovedSpy::refresh);
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
switch (event->state()) {
|
||||
case SwitchEvent::State::Off:
|
||||
m_parent->setIsTablet(false);
|
||||
break;
|
||||
case SwitchEvent::State::On:
|
||||
m_parent->setIsTablet(true);
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
void refresh(LibInput::Device* d) {
|
||||
if (!d->isTouch() && !d->isPointer())
|
||||
return;
|
||||
check();
|
||||
}
|
||||
}
|
||||
|
||||
void check() {
|
||||
if (!LibInput::Connection::self()) {
|
||||
qDebug() << "no libinput :(";
|
||||
return;
|
||||
}
|
||||
const auto devices = LibInput::Connection::self()->devices();
|
||||
const bool hasTouch = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isTouch(); });
|
||||
m_parent->setTabletModeAvailable(hasTouch);
|
||||
|
||||
const bool hasPointer = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isPointer(); });
|
||||
m_parent->setIsTablet(hasTouch && !hasPointer);
|
||||
}
|
||||
|
||||
private:
|
||||
TabletModeManager * const m_parent;
|
||||
};
|
||||
|
||||
TabletModeManager::TabletModeManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_spy(new TabletModeInputEventSpy(this))
|
||||
: QObject(parent)
|
||||
{
|
||||
input()->installInputEventSpy(m_spy);
|
||||
if (input()->hasTabletModeSwitch()) {
|
||||
input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
|
||||
} else {
|
||||
hasTabletModeInputChanged(false);
|
||||
}
|
||||
|
||||
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"),
|
||||
QStringLiteral("org.kde.KWin.TabletModeManager"),
|
||||
|
@ -82,9 +121,29 @@ TabletModeManager::TabletModeManager(QObject *parent)
|
|||
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::tabletModeAvailableChanged);
|
||||
}
|
||||
|
||||
void KWin::TabletModeManager::hasTabletModeInputChanged(bool set)
|
||||
{
|
||||
if (set) {
|
||||
input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
|
||||
setTabletModeAvailable(true);
|
||||
} else {
|
||||
auto setupDetector = [this] {
|
||||
auto spy = new TabletModeTouchpadRemovedSpy(this);
|
||||
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, spy, [spy](bool set){
|
||||
if (set)
|
||||
spy->deleteLater();
|
||||
});
|
||||
};
|
||||
if (LibInput::Connection::self())
|
||||
setupDetector();
|
||||
else
|
||||
QTimer::singleShot(2000, this, setupDetector);
|
||||
}
|
||||
}
|
||||
|
||||
bool TabletModeManager::isTabletModeAvailable() const
|
||||
{
|
||||
return input()->hasTabletModeSwitch();
|
||||
return m_detecting;
|
||||
}
|
||||
|
||||
bool TabletModeManager::isTablet() const
|
||||
|
@ -101,3 +160,11 @@ void TabletModeManager::setIsTablet(bool tablet)
|
|||
m_isTabletMode = tablet;
|
||||
emit tabletModeChanged(tablet);
|
||||
}
|
||||
|
||||
void KWin::TabletModeManager::setTabletModeAvailable(bool detecting)
|
||||
{
|
||||
if (m_detecting != detecting) {
|
||||
m_detecting = detecting;
|
||||
tabletModeAvailableChanged(detecting);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
|
||||
namespace KWin {
|
||||
|
||||
class TabletModeInputEventSpy;
|
||||
|
||||
class TabletModeManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -40,6 +38,7 @@ class TabletModeManager : public QObject
|
|||
public:
|
||||
~TabletModeManager() = default;
|
||||
|
||||
void setTabletModeAvailable(bool detecting);
|
||||
bool isTabletModeAvailable() const;
|
||||
|
||||
bool isTablet() const;
|
||||
|
@ -50,9 +49,11 @@ Q_SIGNALS:
|
|||
void tabletModeChanged(bool tabletMode);
|
||||
|
||||
private:
|
||||
void hasTabletModeInputChanged(bool set);
|
||||
|
||||
bool m_tabletModeAvailable = false;
|
||||
bool m_isTabletMode = false;
|
||||
TabletModeInputEventSpy *m_spy;
|
||||
bool m_detecting = false;
|
||||
KWIN_SINGLETON_VARIABLE(TabletModeManager, s_manager)
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue