Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 71 additions & 1 deletion waylib/src/server/protocols/wxwayland.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

#include "wxwayland.h"

#include "private/wglobal_p.h"

Check warning on line 6 in waylib/src/server/protocols/wxwayland.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "private/wglobal_p.h" not found.
#include "private/wwaylandresource_p.h"

Check warning on line 7 in waylib/src/server/protocols/wxwayland.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "private/wwaylandresource_p.h" not found.
#include "private/wxwaylandsurface_p.h"
#include "wcursor.h"

Check warning on line 9 in waylib/src/server/protocols/wxwayland.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "wcursor.h" not found.
#include "wseat.h"

Check warning on line 10 in waylib/src/server/protocols/wxwayland.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "wseat.h" not found.
#include "wscoplistener.h"

Check warning on line 11 in waylib/src/server/protocols/wxwayland.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "wscoplistener.h" not found.
#include "wsocket.h"

Check warning on line 12 in waylib/src/server/protocols/wxwayland.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "wsocket.h" not found.
#include "wxwaylandsurface.h"

#include <xcb/xcb.h>
Expand Down Expand Up @@ -52,6 +53,12 @@
void on_surface_destroy(WXWaylandSurface *surface);
// end slot function

// Cursor position sync to the Xwayland server.
void syncCursorPositionToXWayland();
void watchSeatCursor();

QMetaObject::Connection cursorPositionChangedConnection;

// Async property reading
struct PerWindowProps
{
Expand Down Expand Up @@ -424,10 +431,69 @@
xcb_flush(connection);
}

void WXWaylandPrivate::syncCursorPositionToXWayland()
{
W_Q(WXWayland);

auto *xwayland = q->handle();
if (!xwayland || !xwayland->seat)
return;

auto *cursor = WSeat::fromHandle(xwayland->seat)->cursor();
if (!cursor)
return;

auto *connection = q->xcbConnection();
if (!connection || !screen)
return;

// Xwayland only learns the pointer position via wl_pointer while the
// pointer is over an X window, so warp the X pointer to the real cursor
// position to keep the global position seen by X clients (e.g. via
// XQueryPointer) fresh while it moves over native Wayland surfaces.
// Warping to the current position (pointer over an X window) is a no-op.
const QPointF pos = cursor->position();
xcb_warp_pointer(connection, XCB_NONE, screen->root,
0, 0, 0, 0, qRound(pos.x()), qRound(pos.y()));
}

void WXWaylandPrivate::watchSeatCursor()
{
W_Q(WXWayland);

// setSeat() may switch to another seat (or clear it), so rebind the
// cursor connection to the current seat on every call. The connection
// is auto-disconnected when the WXWayland instance is destroyed.
if (cursorPositionChangedConnection) {
QObject::disconnect(cursorPositionChangedConnection);
cursorPositionChangedConnection = {};
}

auto *xwayland = q->handle();
auto *seat = xwayland ? xwayland->seat : nullptr;
if (!seat)
return;

if (auto *seatObject = WSeat::fromHandle(seat)) {
if (auto *cursor = seatObject->cursor()) {
cursorPositionChangedConnection = QObject::connect(cursor,
&WCursor::positionChanged,
q, [this] {
syncCursorPositionToXWayland();
});
}
}
}

void WXWayland::setSeat(WSeat *seat)
{
W_D(WXWayland);

if (auto handle = this->handle())
wlr_xwayland_set_seat(handle, seat->handle());
wlr_xwayland_set_seat(handle, seat ? seat->handle() : nullptr);

d->watchSeatCursor();
d->syncCursorPositionToXWayland();
}

WSeat *WXWayland::seat() const
Expand Down Expand Up @@ -545,6 +611,10 @@

listeners()->add(&handle->events.ready, this, [this, d] (void *) {
d->init();
// The seat may be set before the Xwayland server starts; sync the
// current cursor position once the server client is available.
d->watchSeatCursor();
d->syncCursorPositionToXWayland();
Q_EMIT ready();
});

Expand Down
Loading