Handle interaction with window decoration directly in InputRedirection

So far input events were sent through Xwayland which is not needed as
we have all information available. Even more it had the pointer surface
on the wrong window when interacting with decorations as it was on the
window and not on the decoration.
This commit is contained in:
Martin Gräßlin 2015-06-03 18:09:54 +02:00
parent 8b3be23032
commit 1edd689293
4 changed files with 129 additions and 0 deletions

View file

@ -45,6 +45,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QMouseEvent>
#include <QProcess>
#include <QStandardPaths>
#include <QScriptEngine>
@ -2257,6 +2258,45 @@ bool Client::belongsToSameApplication(const AbstractClient *other, bool active_h
return Client::belongToSameApplication(this, c2, active_hack);
}
bool Client::processDecorationButtonPress(QMouseEvent *event)
{
return processDecorationButtonPress(qtToX11Button(event->button()), 0,
event->x(), event->y(),
event->globalX(), event->globalY());
}
void Client::processDecorationButtonRelease(QMouseEvent *event)
{
if (m_decoration) {
if (!event->isAccepted() && m_decoration->titleBar().contains(event->pos()) && event->button() == Qt::LeftButton) {
m_decorationDoubleClickTimer.start();
}
}
if (event->buttons() == Qt::NoButton) {
buttonDown = false;
stopDelayedMoveResize();
if (moveResizeMode) {
finishMoveResize(false);
mode = mousePosition();
}
updateCursor();
}
}
void Client::processDecorationMove()
{
if (buttonDown) {
return;
}
// TODO: handle modifiers
Position newmode = mousePosition();
if (newmode != mode) {
mode = newmode;
updateCursor();
}
}
} // namespace
#include "client.moc"

View file

@ -231,6 +231,9 @@ public:
bool windowEvent(xcb_generic_event_t *e);
void syncEvent(xcb_sync_alarm_notify_event_t* e);
NET::WindowType windowType(bool direct = false, int supported_types = 0) const;
bool processDecorationButtonPress(QMouseEvent *event);
void processDecorationButtonRelease(QMouseEvent *event);
void processDecorationMove();
bool manage(xcb_window_t w, bool isMapped);
void releaseWindow(bool on_shutdown = false);

View file

@ -38,6 +38,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "virtual_terminal.h"
#include <KWayland/Server/seat_interface.h>
#endif
#include <decorations/decoratedclient.h>
#include <KDecoration2/Decoration>
// Qt
#include <QKeyEvent>
#include <QMouseEvent>
@ -375,6 +377,10 @@ void InputRedirection::updatePointerWindow()
{
// TODO: handle pointer grab aka popups
Toplevel *t = findToplevel(m_globalPointer.toPoint());
updatePointerDecoration(t);
if (m_pointerDecoration) {
t = nullptr;
}
auto oldWindow = m_pointerWindow;
if (!oldWindow.isNull() && t == m_pointerWindow.data()) {
return;
@ -416,6 +422,38 @@ void InputRedirection::updatePointerWindow()
m_pointerWindow = QWeakPointer<Toplevel>(t);
}
void InputRedirection::updatePointerDecoration(Toplevel *t)
{
const auto oldDeco = m_pointerDecoration;
if (Client *c = dynamic_cast<Client*>(t)) {
// check whether it's on a Decoration
if (c->decoratedClient()) {
const QRect clientRect = QRect(c->clientPos(), c->clientSize()).translated(c->pos());
if (!clientRect.contains(m_globalPointer.toPoint())) {
m_pointerDecoration = c->decoratedClient();
} else {
m_pointerDecoration.clear();
}
} else {
m_pointerDecoration.clear();
}
} else {
m_pointerDecoration.clear();
}
if (oldDeco && oldDeco != m_pointerDecoration) {
// send leave
QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF());
QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event);
}
if (m_pointerDecoration) {
const QPointF p = m_globalPointer - t->pos();
QHoverEvent event(QEvent::HoverMove, p, p);
QCoreApplication::instance()->sendEvent(m_pointerDecoration->decoration(), &event);
m_pointerDecoration->client()->processDecorationMove();
}
}
void InputRedirection::updateFocusedPointerPosition()
{
#if HAVE_WAYLAND
@ -496,6 +534,23 @@ void InputRedirection::processPointerButton(uint32_t button, InputRedirection::P
}
}
#endif
if (m_pointerDecoration) {
const QPoint localPos = m_globalPointer.toPoint() - m_pointerDecoration->client()->pos();
QMouseEvent event(buttonStateToEvent(state),
localPos,
m_globalPointer.toPoint(),
buttonToQtMouseButton(button), qtButtonStates(), keyboardModifiers());
event.setAccepted(false);
QCoreApplication::sendEvent(m_pointerDecoration->decoration(), &event);
if (!event.isAccepted()) {
if (state == PointerButtonPressed) {
m_pointerDecoration->client()->processDecorationButtonPress(&event);
}
}
if (state == PointerButtonReleased) {
m_pointerDecoration->client()->processDecorationButtonRelease(&event);
}
}
// TODO: check which part of KWin would like to intercept the event
#if HAVE_WAYLAND
if (auto seat = findSeat()) {
@ -536,6 +591,25 @@ void InputRedirection::processPointerAxis(InputRedirection::PointerAxis axis, qr
}
#endif
if (m_pointerDecoration) {
const QPointF localPos = m_globalPointer - m_pointerDecoration->client()->pos();
// TODO: add modifiers and buttons
QWheelEvent event(localPos, m_globalPointer, QPoint(),
(axis == PointerAxisHorizontal) ? QPoint(delta, 0) : QPoint(0, delta),
delta,
(axis == PointerAxisHorizontal) ? Qt::Horizontal : Qt::Vertical,
Qt::NoButton,
Qt::NoModifier);
event.setAccepted(false);
QCoreApplication::sendEvent(m_pointerDecoration->decoration(), &event);
if (!event.isAccepted() && axis == PointerAxisVertical) {
if (m_pointerDecoration->decoration()->titleBar().contains(localPos.toPoint())) {
m_pointerDecoration->client()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1),
m_globalPointer.toPoint());
}
}
}
// TODO: check which part of KWin would like to intercept the event
// TODO: Axis support for effect redirection
#if HAVE_WAYLAND

12
input.h
View file

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QHash>
#include <QObject>
#include <QPoint>
#include <QPointer>
#include <QEvent>
#include <QWeakPointer>
#include <config-kwin.h>
@ -42,6 +43,11 @@ class GlobalShortcutsManager;
class Toplevel;
class Xkb;
namespace Decoration
{
class DecoratedClientImpl;
}
namespace LibInput
{
class Connection;
@ -183,6 +189,7 @@ private:
void updateFocusedPointerPosition();
void updateFocusedTouchPosition();
void updateTouchWindow(const QPointF &pos);
void updatePointerDecoration(Toplevel *t);
bool areButtonsPressed() const;
QPointF m_globalPointer;
QHash<uint32_t, PointerButtonState> m_pointerButtons;
@ -193,6 +200,11 @@ private:
* @brief The Toplevel which currently receives pointer events
*/
QWeakPointer<Toplevel> m_pointerWindow;
/**
* @brief The Decoration which currently receives pointer events.
* Decoration belongs to the pointerWindow
**/
QPointer<Decoration::DecoratedClientImpl> m_pointerDecoration;
/**
* @brief The Toplevel which currently receives touch events
*/