Skip to content

Commit

Permalink
Add alwaysUpdateHoverTarget property for WSeat
Browse files Browse the repository at this point in the history
  • Loading branch information
zccrs committed Nov 6, 2024
1 parent 7101408 commit 4dfba83
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/server/kernel/winputdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <QInputDevice>
#include <QPointer>

#include <private/qpointingdevice_p.h>

QW_USE_NAMESPACE
WAYLIB_SERVER_BEGIN_NAMESPACE

Expand All @@ -35,6 +37,7 @@ class Q_DECL_HIDDEN WInputDevicePrivate : public WWrapObjectPrivate
W_DECLARE_PUBLIC(WInputDevice);

QPointer<QInputDevice> qtDevice;
QPointer<QObject> hoverTarget;
WSeat *seat = nullptr;
};

Expand Down Expand Up @@ -104,4 +107,39 @@ QInputDevice *WInputDevice::qtDevice() const
return d->qtDevice;
}

void WInputDevice::setExclusiveGrabber(QObject *grabber)
{
W_D(WInputDevice);
auto pointerDevice = qobject_cast<QPointingDevice*>(d->qtDevice);
if (!pointerDevice)
return;
auto dd = QPointingDevicePrivate::get(pointerDevice);
if (dd->activePoints.isEmpty())
return;
auto firstPoint = dd->activePoints.values().first();
dd->setExclusiveGrabber(nullptr, firstPoint.eventPoint, grabber);
}

QObject *WInputDevice::exclusiveGrabber() const
{
W_DC(WInputDevice);
auto pointerDevice = qobject_cast<QPointingDevice*>(d->qtDevice);
if (!pointerDevice)
return nullptr;
auto dd = QPointingDevicePrivate::get(pointerDevice);
return dd->firstPointExclusiveGrabber();
}

QObject *WInputDevice::hoverTarget() const
{
W_DC(WInputDevice);
return d->hoverTarget;
}

void WInputDevice::setHoverTarget(QObject *object)
{
W_D(WInputDevice);
d->hoverTarget = object;
}

WAYLIB_SERVER_END_NAMESPACE
9 changes: 9 additions & 0 deletions src/server/kernel/winputdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ QW_END_NAMESPACE

QT_BEGIN_NAMESPACE
class QInputDevice;
class QEventPoint;
QT_END_NAMESPACE

WAYLIB_SERVER_BEGIN_NAMESPACE
Expand Down Expand Up @@ -53,7 +54,15 @@ class WAYLIB_SERVER_EXPORT WInputDevice : public WWrapObject

private:
friend class QWlrootsIntegration;
friend class WSeat;
friend class WSeatPrivate;
void setQtDevice(QInputDevice *device);

void setExclusiveGrabber(QObject *grabber);
QObject *exclusiveGrabber() const;

QObject *hoverTarget() const;
void setHoverTarget(QObject *object);
};

WAYLIB_SERVER_END_NAMESPACE
77 changes: 77 additions & 0 deletions src/server/kernel/wseat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class Q_DECL_HIDDEN WSeatPrivate : public WWrapObjectPrivate
handle()->pointer_notify_frame();
}
inline bool doEnter(WSurface *surface, QObject *eventObject, const QPointF &position) {
qDebug() << surface << "=====================================";
// doEnter be called from QEvent::HoverEnter is normal,
// but doNotifyMotion will call doEnter too,
// so should compare pointerFocusEventObject and eventObject early
Expand Down Expand Up @@ -190,6 +191,7 @@ class Q_DECL_HIDDEN WSeatPrivate : public WWrapObjectPrivate
return true;
}
inline void doClearPointerFocus() {
qDebug() << Q_FUNC_INFO << pointerFocusEventObject << "--------------";
pointerFocusEventObject.clear();
handle()->pointer_notify_clear_focus();
Q_ASSERT(!handle()->handle()->pointer_state.focused_surface);
Expand Down Expand Up @@ -401,6 +403,8 @@ class Q_DECL_HIDDEN WSeatPrivate : public WWrapObjectPrivate
WGlobal::CursorShape cursorShape = WGlobal::CursorShape::Invalid;

QPointer<WSurface> dragSurface;

bool alwaysUpdateHoverTarget = false;
};

void WSeatPrivate::on_destroy()
Expand Down Expand Up @@ -1037,6 +1041,39 @@ void WSeat::setKeyboard(WInputDevice *newKeyboard)
Q_EMIT this->keyboardChanged();
}

bool WSeat::alwaysUpdateHoverTarget() const
{
W_DC(WSeat);
return d->alwaysUpdateHoverTarget;
}

void WSeat::setAlwaysUpdateHoverTarget(bool newIgnoreSurfacePointerEventExclusiveGrabber)
{
W_D(WSeat);
if (d->alwaysUpdateHoverTarget == newIgnoreSurfacePointerEventExclusiveGrabber)
return;
d->alwaysUpdateHoverTarget = newIgnoreSurfacePointerEventExclusiveGrabber;

if (d->alwaysUpdateHoverTarget) {
for (WInputDevice *device : std::as_const(d->deviceList)) {
// Qt will auto grab the pointer event for QQuickItem when mouse pressed
// until mouse released. But we want always update the HoverEnter/Leave's
// WSurfaceItem between drag move.
if (device->exclusiveGrabber() == device->hoverTarget())
device->setExclusiveGrabber(nullptr);
}
} else {
for (WInputDevice *device : std::as_const(d->deviceList)) {
if (!device->exclusiveGrabber()) {
// Restore
device->setExclusiveGrabber(device->hoverTarget());
}
}
}

Q_EMIT alwaysUpdateHoverTargetChanged();
}

void WSeat::notifyMotion(WCursor *cursor, WInputDevice *device, uint32_t timestamp)
{
W_D(WSeat);
Expand Down Expand Up @@ -1434,6 +1471,17 @@ bool WSeat::filterEventBeforeDisposeStage(QWindow *targetWindow, QInputEvent *ev

d->addEventState(event);

if (event->isPointerEvent()) {
auto pe = static_cast<QPointerEvent*>(event);
if (pe->isEndEvent()) {
auto device = WInputDevice::from(event->device());
if (!device->exclusiveGrabber()) {
// Restore the grabber, See alwaysUpdateHoverTarget
device->setExclusiveGrabber(device->hoverTarget());
}
}
}

if (Q_UNLIKELY(d->eventFilter)) {
if (d->eventFilter->beforeDisposeEvent(this, targetWindow, event)) {
if (event->type() == QEvent::MouseMove || event->type() == QEvent::HoverMove) {
Expand All @@ -1444,6 +1492,7 @@ bool WSeat::filterEventBeforeDisposeStage(QWindow *targetWindow, QInputEvent *ev
// because the QQuickDeliveryAgent can't get the real last mouse
// position, the QQuickWindowPrivate::lastMousePosition is error.
if (QQuickWindow *qw = qobject_cast<QQuickWindow*>(targetWindow)) {
Q_ASSERT(event->isSinglePointEvent());
const auto pos = static_cast<QSinglePointEvent*>(event)->position();
QQuickWindowPrivate::get(qw)->deliveryAgentPrivate()->lastMousePosition = pos;
}
Expand All @@ -1456,6 +1505,20 @@ bool WSeat::filterEventBeforeDisposeStage(QWindow *targetWindow, QInputEvent *ev
return false;
}

bool WSeat::filterEventBeforeDisposeStage(QObject *target, QInputEvent *event)
{
if (event->type() == QEvent::HoverEnter) {
auto ie = WInputDevice::from(event->device());
ie->setHoverTarget(target);
} else if (event->type() == QEvent::HoverLeave) {
auto ie = WInputDevice::from(event->device());
if (ie->hoverTarget() == target)
ie->setHoverTarget(nullptr);
}

return false;
}

bool WSeat::filterEventAfterDisposeStage(QWindow *targetWindow, QInputEvent *event)
{
W_D(WSeat);
Expand All @@ -1465,6 +1528,20 @@ bool WSeat::filterEventAfterDisposeStage(QWindow *targetWindow, QInputEvent *eve

if (event->isAccepted() || d->pendingEvents.at(eventStateIndex).isAccepted) {
d->pendingEvents.removeAt(eventStateIndex);

if (event->isPointerEvent()) {
auto pe = static_cast<QPointerEvent*>(event);

// Qt will auto grab the pointer event for QQuickItem when mouse pressed
// until mouse released. But we want always update the HoverEnter/Leave's
// WSurfaceItem between drag move.
if (pe->isBeginEvent()) {
auto ie = WInputDevice::from(event->device());
if (ie->exclusiveGrabber() == ie->hoverTarget())
ie->setExclusiveGrabber(nullptr);
}
}

return false;
}

Expand Down
7 changes: 7 additions & 0 deletions src/server/kernel/wseat.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class WAYLIB_SERVER_EXPORT WSeat : public WWrapObject, public WServerInterface
W_DECLARE_PRIVATE(WSeat)
Q_PROPERTY(WInputDevice* keyboard READ keyboard WRITE setKeyboard NOTIFY keyboardChanged FINAL)
Q_PROPERTY(WSurface* keyboardFocus READ keyboardFocusSurface WRITE setKeyboardFocusSurface NOTIFY keyboardFocusSurfaceChanged FINAL)
Q_PROPERTY(bool alwaysUpdateHoverTarget READ alwaysUpdateHoverTarget WRITE setAlwaysUpdateHoverTarget NOTIFY alwaysUpdateHoverTargetChanged FINAL)

public:
WSeat(const QString &name = QStringLiteral("seat0"));
Expand Down Expand Up @@ -99,12 +100,16 @@ class WAYLIB_SERVER_EXPORT WSeat : public WWrapObject, public WServerInterface
WInputDevice *keyboard() const;
void setKeyboard(WInputDevice *newKeyboard);

bool alwaysUpdateHoverTarget() const;
void setAlwaysUpdateHoverTarget(bool newIgnoreSurfacePointerEventExclusiveGrabber);

Q_SIGNALS:
void keyboardChanged();
void keyboardFocusSurfaceChanged();
void requestCursorShape(WAYLIB_SERVER_NAMESPACE::WGlobal::CursorShape shape);
void requestCursorSurface(WAYLIB_SERVER_NAMESPACE::WSurface *surface, const QPoint &hotspot);
void requestDrag(WAYLIB_SERVER_NAMESPACE::WSurface *surface);
void alwaysUpdateHoverTargetChanged();

protected:
using QObject::eventFilter;
Expand All @@ -114,6 +119,7 @@ class WAYLIB_SERVER_EXPORT WSeat : public WWrapObject, public WServerInterface
friend class QWlrootsRenderWindow;
friend class WEventJunkman;
friend class WCursorShapeManagerV1;
friend class WOutputRenderWindow;

void create(WServer *server) override;
void destroy(WServer *server) override;
Expand All @@ -122,6 +128,7 @@ class WAYLIB_SERVER_EXPORT WSeat : public WWrapObject, public WServerInterface

// for event filter
bool filterEventBeforeDisposeStage(QWindow *targetWindow, QInputEvent *event);
bool filterEventBeforeDisposeStage(QObject *target, QInputEvent *event);
bool filterEventAfterDisposeStage(QWindow *targetWindow, QInputEvent *event);
bool filterUnacceptedEvent(QWindow *targetWindow, QInputEvent *event);

Expand Down
20 changes: 20 additions & 0 deletions src/server/qtquick/woutputrenderwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "wbufferrenderer_p.h"
#include "wquicktextureproxy.h"
#include "weventjunkman.h"
#include "winputdevice.h"
#include "wseat.h"

#include "platformplugin/qwlrootsintegration.h"
#include "platformplugin/qwlrootscreen.h"
Expand Down Expand Up @@ -1518,10 +1520,14 @@ WOutputRenderWindow::WOutputRenderWindow(QObject *parent)
// see [QQuickApplicationWindow](qt6/qtdeclarative/src/quicktemplates/qquickapplicationwindow.cpp)
contentItem()->setFlag(QQuickItem::ItemIsFocusScope);
contentItem()->setFocus(true);

qGuiApp->installEventFilter(this);
}

WOutputRenderWindow::~WOutputRenderWindow()
{
qGuiApp->removeEventFilter(this);

renderControl()->disconnect(this);
renderControl()->invalidate();
renderControl()->deleteLater();
Expand Down Expand Up @@ -1939,6 +1945,20 @@ bool WOutputRenderWindow::event(QEvent *event)
return isAccepted;
}

bool WOutputRenderWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->isInputEvent()) {
auto ie = static_cast<QInputEvent*>(event);
auto device = WInputDevice::from(ie->device());
Q_ASSERT(device);
Q_ASSERT(device->seat());
if (device->seat()->filterEventBeforeDisposeStage(watched, ie))
return true;
}

return QQuickWindow::eventFilter(watched, event);
}

WAYLIB_SERVER_END_NAMESPACE

#include "moc_woutputrenderwindow.cpp"
1 change: 1 addition & 0 deletions src/server/qtquick/woutputrenderwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public Q_SLOTS:
void componentComplete() override;

bool event(QEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;

friend class WOutputViewport;
QList<WOutputLayer*> layers(const WOutputViewport *output) const;
Expand Down

0 comments on commit 4dfba83

Please sign in to comment.