Add support for touch events in the Effect system

Summary:
The Effect class is extended by three new virtual methods:
* touchDown
* touchMotion
* touchUp

The methods return a boolean value so that the events can be filtered
out. E.g. an effect which has also a mouse grab installed wants to
filter out all events, other effects don't need the events exclusively.

This is a difference to how e.g. keyboard and pointer events are handled.
But is more close to how KWin's internal input event passing works and
makes it easier to get touch event: one does not explicitly has to grab
the events. It's also closer to Wayland where all input events are
available.

As a first example the Present Windows effect is adjusted and allows to
activate windows through the touch screen. As much code as possible is
shared with pointer input.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D2450
icc-effect-5.14.5
Martin Gräßlin 2016-08-15 15:44:10 +02:00
parent d68a3fecd7
commit 6af0cc6ebe
7 changed files with 206 additions and 6 deletions

View File

@ -672,6 +672,40 @@ bool EffectsHandlerImpl::isMouseInterception() const
return m_grabbedMouseEffects.count() > 0;
}
bool EffectsHandlerImpl::touchDown(quint32 id, const QPointF &pos, quint32 time)
{
// TODO: reverse call order?
for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
if (it->second->touchDown(id, pos, time)) {
return true;
}
}
return false;
}
bool EffectsHandlerImpl::touchMotion(quint32 id, const QPointF &pos, quint32 time)
{
// TODO: reverse call order?
for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
if (it->second->touchMotion(id, pos, time)) {
return true;
}
}
return false;
}
bool EffectsHandlerImpl::touchUp(quint32 id, quint32 time)
{
// TODO: reverse call order?
for (auto it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); ++it) {
if (it->second->touchUp(id, time)) {
return true;
}
}
return false;
}
void EffectsHandlerImpl::registerGlobalShortcut(const QKeySequence &shortcut, QAction *action)
{
input()->registerShortcut(shortcut, action);

View File

@ -232,6 +232,10 @@ public:
return m_scene;
}
bool touchDown(quint32 id, const QPointF &pos, quint32 time);
bool touchMotion(quint32 id, const QPointF &pos, quint32 time);
bool touchUp(quint32 id, quint32 time);
public Q_SLOTS:
void slotCurrentTabAboutToChange(EffectWindow* from, EffectWindow* to);
void slotTabAdded(EffectWindow* from, EffectWindow* to);

View File

@ -553,6 +553,11 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
}
}
}
inputEventUpdate(me->pos(), me->type(), me->button());
}
void PresentWindowsEffect::inputEventUpdate(const QPoint &pos, QEvent::Type type, Qt::MouseButton button)
{
// Which window are we hovering over? Always trigger as we don't always get move events before clicking
// We cannot use m_motionManager.windowAtPoint() as the window might not be visible
EffectWindowList windows = m_motionManager.managedWindows();
@ -562,7 +567,7 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
DataHash::const_iterator winData = m_windowData.constFind(windows.at(i));
if (winData == m_windowData.constEnd())
continue;
if (m_motionManager.transformedGeometry(windows.at(i)).contains(cursorPos()) &&
if (m_motionManager.transformedGeometry(windows.at(i)).contains(pos) &&
winData->visible && !winData->deleted) {
hovering = true;
if (windows.at(i) && m_highlightedWindow != windows.at(i))
@ -572,15 +577,15 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
}
if (!hovering)
setHighlightedWindow(NULL);
if (m_highlightedWindow && m_motionManager.transformedGeometry(m_highlightedWindow).contains(me->pos()))
if (m_highlightedWindow && m_motionManager.transformedGeometry(m_highlightedWindow).contains(pos))
updateCloseWindow();
else if (m_closeView)
m_closeView->hide();
if (e->type() == QEvent::MouseButtonRelease) {
if (type == QEvent::MouseButtonRelease) {
if (highlightCandidate)
setHighlightedWindow(highlightCandidate);
if (me->button() == Qt::LeftButton) {
if (button == Qt::LeftButton) {
if (hovering) {
// mouse is hovering above a window - use MouseActionsWindow
mouseActionWindow(m_leftButtonWindow);
@ -589,7 +594,7 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
mouseActionDesktop(m_leftButtonDesktop);
}
}
if (me->button() == Qt::MidButton) {
if (button == Qt::MidButton) {
if (hovering) {
// mouse is hovering above a window - use MouseActionsWindow
mouseActionWindow(m_middleButtonWindow);
@ -598,7 +603,7 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
mouseActionDesktop(m_middleButtonDesktop);
}
}
if (me->button() == Qt::RightButton) {
if (button == Qt::RightButton) {
if (hovering) {
// mouse is hovering above a window - use MouseActionsWindow
mouseActionWindow(m_rightButtonWindow);
@ -611,6 +616,52 @@ void PresentWindowsEffect::windowInputMouseEvent(QEvent *e)
setHighlightedWindow(highlightCandidate);
}
bool PresentWindowsEffect::touchDown(quint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(time)
if (!m_activated) {
return false;
}
// only if we don't track a touch id yet
if (!m_touch.active) {
m_touch.active = true;
m_touch.id = id;
inputEventUpdate(pos.toPoint());
}
return true;
}
bool PresentWindowsEffect::touchMotion(quint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(time)
if (!m_activated) {
return false;
}
if (m_touch.active && m_touch.id == id) {
// only update for the touch id we track
inputEventUpdate(pos.toPoint());
}
return true;
}
bool PresentWindowsEffect::touchUp(quint32 id, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(time)
if (!m_activated) {
return false;
}
if (m_touch.active && m_touch.id == id) {
m_touch.active = false;
m_touch.id = 0;
if (m_highlightedWindow) {
mouseActionWindow(m_leftButtonWindow);
}
}
return true;
}
void PresentWindowsEffect::mouseActionWindow(WindowMouseAction& action)
{
switch(action) {

View File

@ -126,6 +126,10 @@ public:
virtual void grabbedKeyboardEvent(QKeyEvent *e);
virtual bool isActive() const;
bool touchDown(quint32 id, const QPointF &pos, quint32 time) override;
bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override;
bool touchUp(quint32 id, quint32 time) override;
int requestedEffectChainPosition() const override {
return 70;
}
@ -265,6 +269,7 @@ protected:
// Helper functions for mouse actions
void mouseActionWindow(WindowMouseAction& action);
void mouseActionDesktop(DesktopMouseAction& action);
void inputEventUpdate(const QPoint &pos, QEvent::Type type = QEvent::None, Qt::MouseButton button = Qt::NoButton);
private:
PresentWindowsEffectProxy m_proxy;
@ -330,6 +335,10 @@ private:
CloseWindowView* m_closeView;
EffectWindow* m_closeWindow;
Qt::Corner m_closeButtonCorner;
struct {
quint32 id = 0;
bool active = false;
} m_touch;
};
} // namespace

View File

@ -344,6 +344,24 @@ public:
static_cast< EffectsHandlerImpl* >(effects)->grabbedKeyboardEvent(event);
return true;
}
bool touchDown(quint32 id, const QPointF &pos, quint32 time) override {
if (!effects) {
return false;
}
return static_cast< EffectsHandlerImpl* >(effects)->touchDown(id, pos, time);
}
bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override {
if (!effects) {
return false;
}
return static_cast< EffectsHandlerImpl* >(effects)->touchMotion(id, pos, time);
}
bool touchUp(quint32 id, quint32 time) override {
if (!effects) {
return false;
}
return static_cast< EffectsHandlerImpl* >(effects)->touchUp(id, time);
}
};
class MoveResizeFilter : public InputEventFilter {

View File

@ -672,6 +672,29 @@ xcb_window_t Effect::x11RootWindow() const
return effects->x11RootWindow();
}
bool Effect::touchDown(quint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(pos)
Q_UNUSED(time)
return false;
}
bool Effect::touchMotion(quint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(pos)
Q_UNUSED(time)
return false;
}
bool Effect::touchUp(quint32 id, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(time)
return false;
}
//****************************************
// EffectFactory
//****************************************

View File

@ -545,6 +545,67 @@ public:
**/
virtual int requestedEffectChainPosition() const;
/**
* A touch point was pressed.
*
* If the effect wants to exclusively use the touch event it should return @c true.
* If @c false is returned the touch event is passed to further effects.
*
* In general an Effect should only return @c true if it is the exclusive effect getting
* input events. E.g. has grabbed mouse events.
*
* Default implementation returns @c false.
*
* @param id The unique id of the touch point
* @param pos The position of the touch point in global coordinates
* @param time Timestamp
*
* @see touchMotion
* @see touchUp
* @since 5.8
**/
virtual bool touchDown(quint32 id, const QPointF &pos, quint32 time);
/**
* A touch point moved.
*
* If the effect wants to exclusively use the touch event it should return @c true.
* If @c false is returned the touch event is passed to further effects.
*
* In general an Effect should only return @c true if it is the exclusive effect getting
* input events. E.g. has grabbed mouse events.
*
* Default implementation returns @c false.
*
* @param id The unique id of the touch point
* @param pos The position of the touch point in global coordinates
* @param time Timestamp
*
* @see touchDown
* @see touchUp
* @since 5.8
**/
virtual bool touchMotion(quint32 id, const QPointF &pos, quint32 time);
/**
* A touch point was released.
*
* If the effect wants to exclusively use the touch event it should return @c true.
* If @c false is returned the touch event is passed to further effects.
*
* In general an Effect should only return @c true if it is the exclusive effect getting
* input events. E.g. has grabbed mouse events.
*
* Default implementation returns @c false.
*
* @param id The unique id of the touch point
* @param time Timestamp
*
* @see touchDown
* @see touchMotion
* @since 5.8
**/
virtual bool touchUp(quint32 id, quint32 time);
static QPoint cursorPos();
/**