Rework cursor image handling for Wayland
So far updating the cursor image was not really defined. It was possible to use the cursor image from the wayland seat or have a custom set cursor image. But there are no rules in place to decide which one to use when. With this change a dedicated CursorImage class is introduced which tracks the cursor image changes on the seat, on the decoration, in the effects and so on. In addition it tracks which is the current source for the image, that is whether e.g. the cursor from the seat or from effects override should be used. Whenever the cursor image changes a signal is emitted, which is connected to the signal in AbstractBackend. Based on that the backends can directly show the image. The existing code in the backends to install a cursor shape or to install the cursor from the server is completely dropped. For the backend it's irrelevant from where the image comes from. A new feature added is that the cursor image is marked as rendered. This is then passed on to the frame rendered in the Surface and thus animated cursors are finally working. Unfortunately animated cursors are broken in Qt (see https://bugreports.qt.io/browse/QTBUG-48181 ).icc-effect-5.14.5
parent
5acf9abda8
commit
a029300ce5
|
@ -23,18 +23,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "composite.h"
|
#include "composite.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "pointer_input.h"
|
||||||
#include "scene_opengl.h"
|
#include "scene_opengl.h"
|
||||||
#include "wayland_server.h"
|
#include "wayland_server.h"
|
||||||
#include "wayland_cursor_theme.h"
|
|
||||||
// KWayland
|
|
||||||
#include <KWayland/Client/buffer.h>
|
|
||||||
#include <KWayland/Client/connection_thread.h>
|
|
||||||
#include <KWayland/Server/buffer_interface.h>
|
|
||||||
#include <KWayland/Server/clientconnection.h>
|
|
||||||
#include <KWayland/Server/seat_interface.h>
|
|
||||||
#include <KWayland/Server/surface_interface.h>
|
|
||||||
// Wayland
|
|
||||||
#include <wayland-cursor.h>
|
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
@ -50,87 +41,14 @@ AbstractBackend::~AbstractBackend()
|
||||||
WaylandServer::self()->uninstallBackend(this);
|
WaylandServer::self()->uninstallBackend(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractBackend::installCursorFromServer()
|
QImage AbstractBackend::softwareCursor() const
|
||||||
{
|
{
|
||||||
if (!m_softWareCursor) {
|
return input()->pointer()->cursorImage();
|
||||||
return;
|
|
||||||
}
|
|
||||||
triggerCursorRepaint();
|
|
||||||
updateCursorFromServer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractBackend::updateCursorFromServer()
|
QPoint AbstractBackend::softwareCursorHotspot() const
|
||||||
{
|
{
|
||||||
if (!waylandServer() || !waylandServer()->seat()->focusedPointer()) {
|
return input()->pointer()->cursorHotSpot();
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto c = waylandServer()->seat()->focusedPointer()->cursor();
|
|
||||||
if (!c) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto cursorSurface = c->surface();
|
|
||||||
if (cursorSurface.isNull()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto buffer = cursorSurface.data()->buffer();
|
|
||||||
if (!buffer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_cursor.hotspot = c->hotspot();
|
|
||||||
m_cursor.image = buffer->data().copy();
|
|
||||||
emit cursorChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractBackend::installCursorImage(Qt::CursorShape shape)
|
|
||||||
{
|
|
||||||
if (!m_softWareCursor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateCursorImage(shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractBackend::updateCursorImage(Qt::CursorShape shape)
|
|
||||||
{
|
|
||||||
if (!m_cursorTheme) {
|
|
||||||
// check whether we can create it
|
|
||||||
if (waylandServer() && waylandServer()->internalShmPool()) {
|
|
||||||
m_cursorTheme = new WaylandCursorTheme(waylandServer()->internalShmPool(), this);
|
|
||||||
connect(waylandServer(), &WaylandServer::terminatingInternalClientConnection, this,
|
|
||||||
[this] {
|
|
||||||
delete m_cursorTheme;
|
|
||||||
m_cursorTheme = nullptr;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_cursorTheme) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wl_cursor_image *cursor = m_cursorTheme->get(shape);
|
|
||||||
if (!cursor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wl_buffer *b = wl_cursor_image_get_buffer(cursor);
|
|
||||||
if (!b) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
waylandServer()->internalClientConection()->flush();
|
|
||||||
waylandServer()->dispatch();
|
|
||||||
installThemeCursor(KWayland::Client::Buffer::getId(b), QPoint(cursor->hotspot_x, cursor->hotspot_y));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractBackend::installThemeCursor(quint32 id, const QPoint &hotspot)
|
|
||||||
{
|
|
||||||
auto buffer = KWayland::Server::BufferInterface::get(waylandServer()->internalConnection()->getResource(id));
|
|
||||||
if (!buffer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_softWareCursor) {
|
|
||||||
triggerCursorRepaint();
|
|
||||||
}
|
|
||||||
m_cursor.hotspot = hotspot;
|
|
||||||
m_cursor.image = buffer->data().copy();
|
|
||||||
emit cursorChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Screens *AbstractBackend::createScreens(QObject *parent)
|
Screens *AbstractBackend::createScreens(QObject *parent)
|
||||||
|
@ -164,17 +82,24 @@ void AbstractBackend::setSoftWareCursor(bool set)
|
||||||
|
|
||||||
void AbstractBackend::triggerCursorRepaint()
|
void AbstractBackend::triggerCursorRepaint()
|
||||||
{
|
{
|
||||||
if (!Compositor::self() || m_cursor.image.isNull()) {
|
if (!Compositor::self()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Compositor::self()->addRepaint(m_cursor.lastRenderedPosition.x() - m_cursor.hotspot.x(),
|
const QPoint &hotSpot = softwareCursorHotspot();
|
||||||
m_cursor.lastRenderedPosition.y() - m_cursor.hotspot.y(),
|
const QSize &size = softwareCursor().size();
|
||||||
m_cursor.image.width(), m_cursor.image.height());
|
Compositor::self()->addRepaint(m_cursor.lastRenderedPosition.x() - hotSpot.x(),
|
||||||
|
m_cursor.lastRenderedPosition.y() - hotSpot.y(),
|
||||||
|
size.width(), size.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractBackend::markCursorAsRendered()
|
void AbstractBackend::markCursorAsRendered()
|
||||||
{
|
{
|
||||||
m_cursor.lastRenderedPosition = Cursor::pos();
|
if (m_softWareCursor) {
|
||||||
|
m_cursor.lastRenderedPosition = Cursor::pos();
|
||||||
|
}
|
||||||
|
if (input()->pointer()) {
|
||||||
|
input()->pointer()->markCursorAsRendered();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractBackend::keyboardKeyPressed(quint32 key, quint32 time)
|
void AbstractBackend::keyboardKeyPressed(quint32 key, quint32 time)
|
||||||
|
|
|
@ -40,8 +40,6 @@ public:
|
||||||
virtual ~AbstractBackend();
|
virtual ~AbstractBackend();
|
||||||
|
|
||||||
virtual void init() = 0;
|
virtual void init() = 0;
|
||||||
virtual void installCursorFromServer();
|
|
||||||
virtual void installCursorImage(Qt::CursorShape shape);
|
|
||||||
virtual Screens *createScreens(QObject *parent = nullptr);
|
virtual Screens *createScreens(QObject *parent = nullptr);
|
||||||
virtual OpenGLBackend *createOpenGLBackend();
|
virtual OpenGLBackend *createOpenGLBackend();
|
||||||
virtual QPainterBackend *createQPainterBackend();
|
virtual QPainterBackend *createQPainterBackend();
|
||||||
|
@ -78,12 +76,8 @@ public:
|
||||||
bool usesSoftwareCursor() const {
|
bool usesSoftwareCursor() const {
|
||||||
return m_softWareCursor;
|
return m_softWareCursor;
|
||||||
}
|
}
|
||||||
QImage softwareCursor() const {
|
QImage softwareCursor() const;
|
||||||
return m_cursor.image;
|
QPoint softwareCursorHotspot() const;
|
||||||
}
|
|
||||||
QPoint softwareCursorHotspot() const {
|
|
||||||
return m_cursor.hotspot;
|
|
||||||
}
|
|
||||||
void markCursorAsRendered();
|
void markCursorAsRendered();
|
||||||
|
|
||||||
bool handlesOutputs() const {
|
bool handlesOutputs() const {
|
||||||
|
@ -143,8 +137,6 @@ Q_SIGNALS:
|
||||||
protected:
|
protected:
|
||||||
explicit AbstractBackend(QObject *parent = nullptr);
|
explicit AbstractBackend(QObject *parent = nullptr);
|
||||||
void setSoftWareCursor(bool set);
|
void setSoftWareCursor(bool set);
|
||||||
void updateCursorFromServer();
|
|
||||||
void updateCursorImage(Qt::CursorShape shape);
|
|
||||||
void handleOutputs() {
|
void handleOutputs() {
|
||||||
m_handlesOutputs = true;
|
m_handlesOutputs = true;
|
||||||
}
|
}
|
||||||
|
@ -162,14 +154,10 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void triggerCursorRepaint();
|
void triggerCursorRepaint();
|
||||||
void installThemeCursor(quint32 id, const QPoint &hotspot);
|
|
||||||
bool m_softWareCursor = false;
|
bool m_softWareCursor = false;
|
||||||
struct {
|
struct {
|
||||||
QPoint hotspot;
|
|
||||||
QImage image;
|
|
||||||
QPoint lastRenderedPosition;
|
QPoint lastRenderedPosition;
|
||||||
} m_cursor;
|
} m_cursor;
|
||||||
WaylandCursorTheme *m_cursorTheme = nullptr;
|
|
||||||
bool m_handlesOutputs = false;
|
bool m_handlesOutputs = false;
|
||||||
bool m_ready = false;
|
bool m_ready = false;
|
||||||
QSize m_initialWindowSize;
|
QSize m_initialWindowSize;
|
||||||
|
|
|
@ -529,16 +529,6 @@ void DrmBackend::present(DrmBuffer *buffer, DrmOutput *output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrmBackend::installCursorFromServer()
|
|
||||||
{
|
|
||||||
updateCursorFromServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrmBackend::installCursorImage(Qt::CursorShape shape)
|
|
||||||
{
|
|
||||||
updateCursorImage(shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrmBackend::initCursor()
|
void DrmBackend::initCursor()
|
||||||
{
|
{
|
||||||
uint64_t capability = 0;
|
uint64_t capability = 0;
|
||||||
|
@ -562,7 +552,6 @@ void DrmBackend::initCursor()
|
||||||
// now we have screens and can set cursors, so start tracking
|
// now we have screens and can set cursors, so start tracking
|
||||||
connect(this, &DrmBackend::cursorChanged, this, &DrmBackend::updateCursor);
|
connect(this, &DrmBackend::cursorChanged, this, &DrmBackend::updateCursor);
|
||||||
connect(Cursor::self(), &Cursor::posChanged, this, &DrmBackend::moveCursor);
|
connect(Cursor::self(), &Cursor::posChanged, this, &DrmBackend::moveCursor);
|
||||||
installCursorImage(Qt::ArrowCursor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrmBackend::setCursor()
|
void DrmBackend::setCursor()
|
||||||
|
@ -572,6 +561,7 @@ void DrmBackend::setCursor()
|
||||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||||
(*it)->showCursor(c);
|
(*it)->showCursor(c);
|
||||||
}
|
}
|
||||||
|
markCursorAsRendered();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrmBackend::updateCursor()
|
void DrmBackend::updateCursor()
|
||||||
|
|
|
@ -71,8 +71,6 @@ public:
|
||||||
Screens *createScreens(QObject *parent = nullptr) override;
|
Screens *createScreens(QObject *parent = nullptr) override;
|
||||||
QPainterBackend *createQPainterBackend() override;
|
QPainterBackend *createQPainterBackend() override;
|
||||||
OpenGLBackend* createOpenGLBackend() override;
|
OpenGLBackend* createOpenGLBackend() override;
|
||||||
void installCursorFromServer() override;
|
|
||||||
void installCursorImage(Qt::CursorShape shape) override;
|
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
DrmBuffer *createBuffer(const QSize &size);
|
DrmBuffer *createBuffer(const QSize &size);
|
||||||
|
|
|
@ -68,7 +68,6 @@ WaylandSeat::WaylandSeat(wl_seat *seat, WaylandBackend *backend)
|
||||||
, m_keyboard(NULL)
|
, m_keyboard(NULL)
|
||||||
, m_touch(nullptr)
|
, m_touch(nullptr)
|
||||||
, m_cursor(NULL)
|
, m_cursor(NULL)
|
||||||
, m_theme(new WaylandCursorTheme(backend->shmPool(), this))
|
|
||||||
, m_enteredSerial(0)
|
, m_enteredSerial(0)
|
||||||
, m_backend(backend)
|
, m_backend(backend)
|
||||||
, m_installCursor(false)
|
, m_installCursor(false)
|
||||||
|
@ -244,21 +243,15 @@ void WaylandSeat::installCursorImage(wl_buffer *image, const QSize &size, const
|
||||||
m_cursor->attachBuffer(image);
|
m_cursor->attachBuffer(image);
|
||||||
m_cursor->damage(QRect(QPoint(0,0), size));
|
m_cursor->damage(QRect(QPoint(0,0), size));
|
||||||
m_cursor->commit(Surface::CommitFlag::None);
|
m_cursor->commit(Surface::CommitFlag::None);
|
||||||
}
|
m_backend->flush();
|
||||||
|
|
||||||
void WaylandSeat::installCursorImage(Qt::CursorShape shape)
|
|
||||||
{
|
|
||||||
wl_cursor_image *image = m_theme->get(shape);
|
|
||||||
if (!image) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
installCursorImage(wl_cursor_image_get_buffer(image),
|
|
||||||
QSize(image->width, image->height),
|
|
||||||
QPoint(image->hotspot_x, image->hotspot_y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandSeat::installCursorImage(const QImage &image, const QPoint &hotSpot)
|
void WaylandSeat::installCursorImage(const QImage &image, const QPoint &hotSpot)
|
||||||
{
|
{
|
||||||
|
if (image.isNull()) {
|
||||||
|
installCursorImage(nullptr, QSize(), QPoint());
|
||||||
|
return;
|
||||||
|
}
|
||||||
installCursorImage(*(m_backend->shmPool()->createBuffer(image).data()), image.size(), hotSpot);
|
installCursorImage(*(m_backend->shmPool()->createBuffer(image).data()), image.size(), hotSpot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,6 +330,15 @@ void WaylandBackend::init()
|
||||||
if (!deviceIdentifier().isEmpty()) {
|
if (!deviceIdentifier().isEmpty()) {
|
||||||
m_connectionThreadObject->setSocketName(deviceIdentifier());
|
m_connectionThreadObject->setSocketName(deviceIdentifier());
|
||||||
}
|
}
|
||||||
|
connect(this, &WaylandBackend::cursorChanged, this,
|
||||||
|
[this] {
|
||||||
|
if (m_seat.isNull() || !m_seat->isInstallCursor()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_seat->installCursorImage(softwareCursor(), softwareCursorHotspot());
|
||||||
|
markCursorAsRendered();
|
||||||
|
}
|
||||||
|
);
|
||||||
initConnection();
|
initConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,35 +391,6 @@ void WaylandBackend::initConnection()
|
||||||
m_connectionThreadObject->initConnection();
|
m_connectionThreadObject->initConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandBackend::installCursorImage(Qt::CursorShape shape)
|
|
||||||
{
|
|
||||||
if (!m_seat.isNull() && m_seat->isInstallCursor()) {
|
|
||||||
m_seat->installCursorImage(shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaylandBackend::installCursorFromServer()
|
|
||||||
{
|
|
||||||
if (!waylandServer() || !waylandServer()->seat()->focusedPointer()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto c = waylandServer()->seat()->focusedPointer()->cursor();
|
|
||||||
if (c) {
|
|
||||||
auto cursorSurface = c->surface();
|
|
||||||
if (!cursorSurface.isNull()) {
|
|
||||||
auto buffer = cursorSurface.data()->buffer();
|
|
||||||
if (buffer) {
|
|
||||||
// set cursor
|
|
||||||
if (!m_seat.isNull() && m_seat->isInstallCursor()) {
|
|
||||||
m_seat->installCursorImage(buffer->data(), c->hotspot());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: unset cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaylandBackend::createSurface()
|
void WaylandBackend::createSurface()
|
||||||
{
|
{
|
||||||
m_surface = m_compositor->createSurface(this);
|
m_surface = m_compositor->createSurface(this);
|
||||||
|
@ -478,6 +451,13 @@ QPainterBackend *WaylandBackend::createQPainterBackend()
|
||||||
return new WaylandQPainterBackend(this);
|
return new WaylandQPainterBackend(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaylandBackend::flush()
|
||||||
|
{
|
||||||
|
if (m_connectionThreadObject) {
|
||||||
|
m_connectionThreadObject->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // KWin
|
} // KWin
|
||||||
|
|
|
@ -74,7 +74,6 @@ public:
|
||||||
virtual ~WaylandSeat();
|
virtual ~WaylandSeat();
|
||||||
|
|
||||||
void installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot);
|
void installCursorImage(wl_buffer *image, const QSize &size, const QPoint &hotspot);
|
||||||
void installCursorImage(Qt::CursorShape shape);
|
|
||||||
void installCursorImage(const QImage &image, const QPoint &hotspot);
|
void installCursorImage(const QImage &image, const QPoint &hotspot);
|
||||||
void setInstallCursor(bool install);
|
void setInstallCursor(bool install);
|
||||||
bool isInstallCursor() const {
|
bool isInstallCursor() const {
|
||||||
|
@ -89,7 +88,6 @@ private:
|
||||||
KWayland::Client::Keyboard *m_keyboard;
|
KWayland::Client::Keyboard *m_keyboard;
|
||||||
KWayland::Client::Touch *m_touch;
|
KWayland::Client::Touch *m_touch;
|
||||||
KWayland::Client::Surface *m_cursor;
|
KWayland::Client::Surface *m_cursor;
|
||||||
WaylandCursorTheme *m_theme = nullptr;
|
|
||||||
uint32_t m_enteredSerial;
|
uint32_t m_enteredSerial;
|
||||||
WaylandBackend *m_backend;
|
WaylandBackend *m_backend;
|
||||||
bool m_installCursor;
|
bool m_installCursor;
|
||||||
|
@ -116,8 +114,6 @@ public:
|
||||||
|
|
||||||
KWayland::Client::Surface *surface() const;
|
KWayland::Client::Surface *surface() const;
|
||||||
QSize shellSurfaceSize() const;
|
QSize shellSurfaceSize() const;
|
||||||
void installCursorImage(Qt::CursorShape shape) override;
|
|
||||||
void installCursorFromServer() override;
|
|
||||||
|
|
||||||
Screens *createScreens(QObject *parent = nullptr) override;
|
Screens *createScreens(QObject *parent = nullptr) override;
|
||||||
OpenGLBackend *createOpenGLBackend() override;
|
OpenGLBackend *createOpenGLBackend() override;
|
||||||
|
@ -127,6 +123,8 @@ public:
|
||||||
return shellSurfaceSize();
|
return shellSurfaceSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flush();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void shellSurfaceSizeChanged(const QSize &size);
|
void shellSurfaceSizeChanged(const QSize &size);
|
||||||
void systemCompositorDied();
|
void systemCompositorDied();
|
||||||
|
|
|
@ -93,6 +93,11 @@ void X11WindowedBackend::init()
|
||||||
XRenderUtils::init(m_connection, m_screen->root);
|
XRenderUtils::init(m_connection, m_screen->root);
|
||||||
createWindow();
|
createWindow();
|
||||||
startEventReading();
|
startEventReading();
|
||||||
|
connect(this, &X11WindowedBackend::cursorChanged, this,
|
||||||
|
[this] {
|
||||||
|
createCursor(softwareCursor(), softwareCursorHotspot());
|
||||||
|
}
|
||||||
|
);
|
||||||
setReady(true);
|
setReady(true);
|
||||||
waylandServer()->seat()->setHasPointer(true);
|
waylandServer()->seat()->setHasPointer(true);
|
||||||
waylandServer()->seat()->setHasKeyboard(true);
|
waylandServer()->seat()->setHasKeyboard(true);
|
||||||
|
@ -374,25 +379,6 @@ void X11WindowedBackend::updateSize(xcb_configure_notify_event_t *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11WindowedBackend::installCursorFromServer()
|
|
||||||
{
|
|
||||||
if (!waylandServer() || !waylandServer()->seat()->focusedPointer()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto c = waylandServer()->seat()->focusedPointer()->cursor();
|
|
||||||
if (c) {
|
|
||||||
auto cursorSurface = c->surface();
|
|
||||||
if (!cursorSurface.isNull()) {
|
|
||||||
auto buffer = cursorSurface.data()->buffer();
|
|
||||||
if (buffer) {
|
|
||||||
createCursor(buffer->data(), c->hotspot());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: unset cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
void X11WindowedBackend::createCursor(const QImage &img, const QPoint &hotspot)
|
void X11WindowedBackend::createCursor(const QImage &img, const QPoint &hotspot)
|
||||||
{
|
{
|
||||||
const xcb_pixmap_t pix = xcb_generate_id(m_connection);
|
const xcb_pixmap_t pix = xcb_generate_id(m_connection);
|
||||||
|
@ -417,13 +403,7 @@ void X11WindowedBackend::createCursor(const QImage &img, const QPoint &hotspot)
|
||||||
}
|
}
|
||||||
m_cursor = cid;
|
m_cursor = cid;
|
||||||
xcb_flush(m_connection);
|
xcb_flush(m_connection);
|
||||||
}
|
markCursorAsRendered();
|
||||||
|
|
||||||
void X11WindowedBackend::installCursorImage(Qt::CursorShape shape)
|
|
||||||
{
|
|
||||||
// TODO: only update if shape changed
|
|
||||||
updateCursorImage(shape);
|
|
||||||
createCursor(softwareCursor(), softwareCursorHotspot());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_window_t X11WindowedBackend::rootWindow() const
|
xcb_window_t X11WindowedBackend::rootWindow() const
|
||||||
|
|
|
@ -63,9 +63,6 @@ public:
|
||||||
}
|
}
|
||||||
xcb_window_t rootWindow() const;
|
xcb_window_t rootWindow() const;
|
||||||
|
|
||||||
void installCursorFromServer() override;
|
|
||||||
void installCursorImage(Qt::CursorShape shape) override;
|
|
||||||
|
|
||||||
Screens *createScreens(QObject *parent = nullptr) override;
|
Screens *createScreens(QObject *parent = nullptr) override;
|
||||||
OpenGLBackend *createOpenGLBackend() override;
|
OpenGLBackend *createOpenGLBackend() override;
|
||||||
QPainterBackend* createQPainterBackend() override;
|
QPainterBackend* createQPainterBackend() override;
|
||||||
|
|
17
effects.cpp
17
effects.cpp
|
@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
|
#include "pointer_input.h"
|
||||||
#include "scene_xrender.h"
|
#include "scene_xrender.h"
|
||||||
#include "scene_qpainter.h"
|
#include "scene_qpainter.h"
|
||||||
#include "unmanaged.h"
|
#include "unmanaged.h"
|
||||||
|
@ -709,9 +710,7 @@ void EffectsHandlerImpl::startMouseInterception(Effect *effect, Qt::CursorShape
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
||||||
if (AbstractBackend *w = waylandServer()->backend()) {
|
input()->pointer()->setEffectsOverrideCursor(shape);
|
||||||
w->installCursorImage(shape);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// NOTE: it is intended to not perform an XPointerGrab on X11. See documentation in kwineffects.h
|
// NOTE: it is intended to not perform an XPointerGrab on X11. See documentation in kwineffects.h
|
||||||
|
@ -743,6 +742,7 @@ void EffectsHandlerImpl::stopMouseInterception(Effect *effect)
|
||||||
}
|
}
|
||||||
m_grabbedMouseEffects.removeAll(effect);
|
m_grabbedMouseEffects.removeAll(effect);
|
||||||
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
if (kwinApp()->operationMode() != Application::OperationModeX11) {
|
||||||
|
input()->pointer()->removeEffectsOverrideCursor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_grabbedMouseEffects.isEmpty()) {
|
if (m_grabbedMouseEffects.isEmpty()) {
|
||||||
|
@ -751,6 +751,11 @@ void EffectsHandlerImpl::stopMouseInterception(Effect *effect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EffectsHandlerImpl::isMouseInterception() const
|
||||||
|
{
|
||||||
|
return m_grabbedMouseEffects.count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
void EffectsHandlerImpl::registerGlobalShortcut(const QKeySequence &shortcut, QAction *action)
|
void EffectsHandlerImpl::registerGlobalShortcut(const QKeySequence &shortcut, QAction *action)
|
||||||
{
|
{
|
||||||
input()->registerShortcut(shortcut, action);
|
input()->registerShortcut(shortcut, action);
|
||||||
|
@ -1225,11 +1230,7 @@ QSize EffectsHandlerImpl::virtualScreenSize() const
|
||||||
void EffectsHandlerImpl::defineCursor(Qt::CursorShape shape)
|
void EffectsHandlerImpl::defineCursor(Qt::CursorShape shape)
|
||||||
{
|
{
|
||||||
if (!m_mouseInterceptionWindow.isValid()) {
|
if (!m_mouseInterceptionWindow.isValid()) {
|
||||||
if (waylandServer()) {
|
input()->pointer()->setEffectsOverrideCursor(shape);
|
||||||
if (AbstractBackend *w = waylandServer()->backend()) {
|
|
||||||
w->installCursorImage(shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const xcb_cursor_t c = Cursor::x11Cursor(shape);
|
const xcb_cursor_t c = Cursor::x11Cursor(shape);
|
||||||
|
|
|
@ -123,6 +123,7 @@ public:
|
||||||
// not performing XGrabPointer
|
// not performing XGrabPointer
|
||||||
void startMouseInterception(Effect *effect, Qt::CursorShape shape) override;
|
void startMouseInterception(Effect *effect, Qt::CursorShape shape) override;
|
||||||
void stopMouseInterception(Effect *effect) override;
|
void stopMouseInterception(Effect *effect) override;
|
||||||
|
bool isMouseInterception() const;
|
||||||
void registerGlobalShortcut(const QKeySequence &shortcut, QAction *action) override;
|
void registerGlobalShortcut(const QKeySequence &shortcut, QAction *action) override;
|
||||||
void registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action) override;
|
void registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action) override;
|
||||||
void registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action) override;
|
void registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action) override;
|
||||||
|
|
|
@ -443,7 +443,6 @@ public:
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
decoration->client()->processDecorationButtonRelease(&e);
|
decoration->client()->processDecorationButtonRelease(&e);
|
||||||
}
|
}
|
||||||
input()->pointer()->installCursorFromDecoration();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -19,20 +19,29 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#include "pointer_input.h"
|
#include "pointer_input.h"
|
||||||
#include "abstract_backend.h"
|
#include "abstract_backend.h"
|
||||||
|
#include "effects.h"
|
||||||
#include "screens.h"
|
#include "screens.h"
|
||||||
#include "shell_client.h"
|
#include "shell_client.h"
|
||||||
|
#include "wayland_cursor_theme.h"
|
||||||
#include "wayland_server.h"
|
#include "wayland_server.h"
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
#include "decorations/decoratedclient.h"
|
#include "decorations/decoratedclient.h"
|
||||||
// KDecoration
|
// KDecoration
|
||||||
#include <KDecoration2/Decoration>
|
#include <KDecoration2/Decoration>
|
||||||
// KWayland
|
// KWayland
|
||||||
|
#include <KWayland/Client/connection_thread.h>
|
||||||
|
#include <KWayland/Client/buffer.h>
|
||||||
|
#include <KWayland/Server/buffer_interface.h>
|
||||||
|
#include <KWayland/Server/display.h>
|
||||||
#include <KWayland/Server/seat_interface.h>
|
#include <KWayland/Server/seat_interface.h>
|
||||||
|
#include <KWayland/Server/surface_interface.h>
|
||||||
// screenlocker
|
// screenlocker
|
||||||
#include <KScreenLocker/KsldApp>
|
#include <KScreenLocker/KsldApp>
|
||||||
|
|
||||||
#include <QHoverEvent>
|
#include <QHoverEvent>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
|
// Wayland
|
||||||
|
#include <wayland-cursor.h>
|
||||||
|
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
@ -100,6 +109,7 @@ static bool screenContainsPos(const QPointF &pos)
|
||||||
PointerInputRedirection::PointerInputRedirection(InputRedirection* parent)
|
PointerInputRedirection::PointerInputRedirection(InputRedirection* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_input(parent)
|
, m_input(parent)
|
||||||
|
, m_cursor(nullptr)
|
||||||
, m_supportsWarping(Application::usesLibinput())
|
, m_supportsWarping(Application::usesLibinput())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -109,7 +119,10 @@ PointerInputRedirection::~PointerInputRedirection() = default;
|
||||||
void PointerInputRedirection::init()
|
void PointerInputRedirection::init()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_inited);
|
Q_ASSERT(!m_inited);
|
||||||
|
m_cursor = new CursorImage(this);
|
||||||
m_inited = true;
|
m_inited = true;
|
||||||
|
connect(m_cursor, &CursorImage::changed, waylandServer()->backend(), &AbstractBackend::cursorChanged);
|
||||||
|
emit m_cursor->changed();
|
||||||
connect(workspace(), &Workspace::stackingOrderChanged, this, &PointerInputRedirection::update);
|
connect(workspace(), &Workspace::stackingOrderChanged, this, &PointerInputRedirection::update);
|
||||||
connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange);
|
connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange);
|
||||||
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &PointerInputRedirection::update);
|
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &PointerInputRedirection::update);
|
||||||
|
@ -219,6 +232,9 @@ void PointerInputRedirection::update()
|
||||||
if (m_decoration || m_internalWindow) {
|
if (m_decoration || m_internalWindow) {
|
||||||
t = nullptr;
|
t = nullptr;
|
||||||
}
|
}
|
||||||
|
if (m_decoration != oldDeco) {
|
||||||
|
emit decorationChanged();
|
||||||
|
}
|
||||||
auto oldWindow = m_window;
|
auto oldWindow = m_window;
|
||||||
if (!oldWindow.isNull() && t == m_window.data()) {
|
if (!oldWindow.isNull() && t == m_window.data()) {
|
||||||
return;
|
return;
|
||||||
|
@ -231,11 +247,6 @@ void PointerInputRedirection::update()
|
||||||
}
|
}
|
||||||
disconnect(m_windowGeometryConnection);
|
disconnect(m_windowGeometryConnection);
|
||||||
m_windowGeometryConnection = QMetaObject::Connection();
|
m_windowGeometryConnection = QMetaObject::Connection();
|
||||||
if (auto p = seat->focusedPointer()) {
|
|
||||||
if (auto c = p->cursor()) {
|
|
||||||
disconnect(c, &KWayland::Server::Cursor::changed, waylandServer()->backend(), &AbstractBackend::installCursorFromServer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (AbstractClient *c = qobject_cast<AbstractClient*>(t)) {
|
if (AbstractClient *c = qobject_cast<AbstractClient*>(t)) {
|
||||||
// only send enter if it wasn't on deco for the same client before
|
// only send enter if it wasn't on deco for the same client before
|
||||||
|
@ -263,12 +274,6 @@ void PointerInputRedirection::update()
|
||||||
seat->setFocusedPointerSurfaceTransformation(m_window.data()->inputTransformation());
|
seat->setFocusedPointerSurfaceTransformation(m_window.data()->inputTransformation());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
waylandServer()->backend()->installCursorFromServer();
|
|
||||||
if (auto p = seat->focusedPointer()) {
|
|
||||||
if (auto c = p->cursor()) {
|
|
||||||
connect(c, &KWayland::Server::Cursor::changed, waylandServer()->backend(), &AbstractBackend::installCursorFromServer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
seat->setFocusedPointerSurface(nullptr);
|
seat->setFocusedPointerSurface(nullptr);
|
||||||
t = nullptr;
|
t = nullptr;
|
||||||
|
@ -372,9 +377,6 @@ void PointerInputRedirection::updateDecoration(Toplevel *t)
|
||||||
// send leave
|
// send leave
|
||||||
QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF());
|
QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF());
|
||||||
QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event);
|
QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event);
|
||||||
if (!m_decoration) {
|
|
||||||
waylandServer()->backend()->installCursorImage(Qt::ArrowCursor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_decoration) {
|
if (m_decoration) {
|
||||||
if (m_decoration->client() != oldWindow) {
|
if (m_decoration->client() != oldWindow) {
|
||||||
|
@ -385,7 +387,6 @@ void PointerInputRedirection::updateDecoration(Toplevel *t)
|
||||||
QHoverEvent event(QEvent::HoverMove, p, p);
|
QHoverEvent event(QEvent::HoverMove, p, p);
|
||||||
QCoreApplication::instance()->sendEvent(m_decoration->decoration(), &event);
|
QCoreApplication::instance()->sendEvent(m_decoration->decoration(), &event);
|
||||||
m_decoration->client()->processDecorationMove();
|
m_decoration->client()->processDecorationMove();
|
||||||
installCursorFromDecoration();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,14 +446,6 @@ bool PointerInputRedirection::supportsWarping() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointerInputRedirection::installCursorFromDecoration()
|
|
||||||
{
|
|
||||||
if (!m_inited || !m_decoration) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
waylandServer()->backend()->installCursorImage(m_decoration->client()->cursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
void PointerInputRedirection::updateAfterScreenChange()
|
void PointerInputRedirection::updateAfterScreenChange()
|
||||||
{
|
{
|
||||||
if (!m_inited) {
|
if (!m_inited) {
|
||||||
|
@ -468,4 +461,286 @@ void PointerInputRedirection::updateAfterScreenChange()
|
||||||
processMotion(pos, waylandServer()->seat()->timestamp());
|
processMotion(pos, waylandServer()->seat()->timestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage PointerInputRedirection::cursorImage() const
|
||||||
|
{
|
||||||
|
if (!m_inited) {
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
return m_cursor->image();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint PointerInputRedirection::cursorHotSpot() const
|
||||||
|
{
|
||||||
|
if (!m_inited) {
|
||||||
|
return QPoint();
|
||||||
|
}
|
||||||
|
return m_cursor->hotSpot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerInputRedirection::markCursorAsRendered()
|
||||||
|
{
|
||||||
|
if (!m_inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_cursor->markAsRendered();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerInputRedirection::setEffectsOverrideCursor(Qt::CursorShape shape)
|
||||||
|
{
|
||||||
|
if (!m_inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_cursor->setEffectsOverrideCursor(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerInputRedirection::removeEffectsOverrideCursor()
|
||||||
|
{
|
||||||
|
if (!m_inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_cursor->removeEffectsOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorImage::CursorImage(PointerInputRedirection *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_pointer(parent)
|
||||||
|
{
|
||||||
|
connect(waylandServer()->seat(), &KWayland::Server::SeatInterface::focusedPointerChanged, this, &CursorImage::update);
|
||||||
|
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &CursorImage::reevaluteSource);
|
||||||
|
connect(m_pointer, &PointerInputRedirection::decorationChanged, this, &CursorImage::updateDecoration);
|
||||||
|
loadThemeCursor(Qt::ArrowCursor, &m_fallbackCursor);
|
||||||
|
m_surfaceRenderedTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorImage::~CursorImage() = default;
|
||||||
|
|
||||||
|
void CursorImage::markAsRendered()
|
||||||
|
{
|
||||||
|
if (m_currentSource != CursorSource::LockScreen && m_currentSource != CursorSource::PointerSurface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto p = waylandServer()->seat()->focusedPointer();
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto c = p->cursor();
|
||||||
|
if (!c) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cursorSurface = c->surface();
|
||||||
|
if (cursorSurface.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cursorSurface->frameRendered(m_surfaceRenderedTimer.elapsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::update()
|
||||||
|
{
|
||||||
|
using namespace KWayland::Server;
|
||||||
|
disconnect(m_serverCursor.connection);
|
||||||
|
auto p = waylandServer()->seat()->focusedPointer();
|
||||||
|
if (p) {
|
||||||
|
m_serverCursor.connection = connect(p, &PointerInterface::cursorChanged, this, &CursorImage::updateServerCursor);
|
||||||
|
} else {
|
||||||
|
m_serverCursor.connection = QMetaObject::Connection();
|
||||||
|
}
|
||||||
|
updateServerCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::updateDecoration()
|
||||||
|
{
|
||||||
|
disconnect(m_decorationConnection);
|
||||||
|
auto deco = m_pointer->decoration();
|
||||||
|
AbstractClient *c = deco.isNull() ? nullptr : deco->client();
|
||||||
|
if (c) {
|
||||||
|
m_decorationConnection = connect(c, &AbstractClient::moveResizeCursorChanged, this, &CursorImage::updateDecorationCursor);
|
||||||
|
} else {
|
||||||
|
m_decorationConnection = QMetaObject::Connection();
|
||||||
|
}
|
||||||
|
updateDecorationCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::updateDecorationCursor()
|
||||||
|
{
|
||||||
|
m_decorationCursor.image = QImage();
|
||||||
|
m_decorationCursor.hotSpot = QPoint();
|
||||||
|
|
||||||
|
auto deco = m_pointer->decoration();
|
||||||
|
if (AbstractClient *c = deco.isNull() ? nullptr : deco->client()) {
|
||||||
|
loadThemeCursor(c->cursor(), &m_decorationCursor);
|
||||||
|
if (m_currentSource == CursorSource::Decoration) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reevaluteSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::updateServerCursor()
|
||||||
|
{
|
||||||
|
m_serverCursor.image = QImage();
|
||||||
|
m_serverCursor.hotSpot = QPoint();
|
||||||
|
reevaluteSource();
|
||||||
|
const bool needsEmit = m_currentSource == CursorSource::LockScreen || m_currentSource == CursorSource::PointerSurface;
|
||||||
|
auto p = waylandServer()->seat()->focusedPointer();
|
||||||
|
if (!p) {
|
||||||
|
if (needsEmit) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto c = p->cursor();
|
||||||
|
if (!c) {
|
||||||
|
if (needsEmit) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cursorSurface = c->surface();
|
||||||
|
if (cursorSurface.isNull()) {
|
||||||
|
if (needsEmit) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto buffer = cursorSurface.data()->buffer();
|
||||||
|
if (!buffer) {
|
||||||
|
if (needsEmit) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_serverCursor.hotSpot = c->hotspot();
|
||||||
|
m_serverCursor.image = buffer->data().copy();
|
||||||
|
if (needsEmit) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::loadTheme()
|
||||||
|
{
|
||||||
|
if (m_cursorTheme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check whether we can create it
|
||||||
|
if (waylandServer()->internalShmPool()) {
|
||||||
|
m_cursorTheme = new WaylandCursorTheme(waylandServer()->internalShmPool(), this);
|
||||||
|
connect(waylandServer(), &WaylandServer::terminatingInternalClientConnection, this,
|
||||||
|
[this] {
|
||||||
|
delete m_cursorTheme;
|
||||||
|
m_cursorTheme = nullptr;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::setEffectsOverrideCursor(Qt::CursorShape shape)
|
||||||
|
{
|
||||||
|
loadThemeCursor(shape, &m_effectsCursor);
|
||||||
|
if (m_currentSource == CursorSource::EffectsOverride) {
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
reevaluteSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::removeEffectsOverrideCursor()
|
||||||
|
{
|
||||||
|
reevaluteSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::loadThemeCursor(Qt::CursorShape shape, Image *image)
|
||||||
|
{
|
||||||
|
loadTheme();
|
||||||
|
if (!m_cursorTheme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto it = m_cursors.constFind(shape);
|
||||||
|
if (it == m_cursors.constEnd()) {
|
||||||
|
image->image = QImage();
|
||||||
|
image->hotSpot = QPoint();
|
||||||
|
wl_cursor_image *cursor = m_cursorTheme->get(shape);
|
||||||
|
if (!cursor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_buffer *b = wl_cursor_image_get_buffer(cursor);
|
||||||
|
if (!b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
waylandServer()->internalClientConection()->flush();
|
||||||
|
waylandServer()->dispatch();
|
||||||
|
auto buffer = KWayland::Server::BufferInterface::get(waylandServer()->internalConnection()->getResource(KWayland::Client::Buffer::getId(b)));
|
||||||
|
if (!buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
it = decltype(it)(m_cursors.insert(shape, {buffer->data().copy(), QPoint(cursor->hotspot_x, cursor->hotspot_y)}));
|
||||||
|
}
|
||||||
|
image->hotSpot = it.value().hotSpot;
|
||||||
|
image->image = it.value().image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::reevaluteSource()
|
||||||
|
{
|
||||||
|
if (waylandServer()->isScreenLocked()) {
|
||||||
|
setSource(CursorSource::LockScreen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (effects && static_cast<EffectsHandlerImpl*>(effects)->isMouseInterception()) {
|
||||||
|
setSource(CursorSource::EffectsOverride);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!m_pointer->decoration().isNull()) {
|
||||||
|
setSource(CursorSource::Decoration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!m_pointer->window().isNull()) {
|
||||||
|
setSource(CursorSource::PointerSurface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSource(CursorSource::Fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CursorImage::setSource(CursorSource source)
|
||||||
|
{
|
||||||
|
if (m_currentSource == source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_currentSource = source;
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage CursorImage::image() const
|
||||||
|
{
|
||||||
|
switch (m_currentSource) {
|
||||||
|
case CursorSource::EffectsOverride:
|
||||||
|
return m_effectsCursor.image;
|
||||||
|
case CursorSource::LockScreen:
|
||||||
|
case CursorSource::PointerSurface:
|
||||||
|
// lockscreen also uses server cursor image
|
||||||
|
return m_serverCursor.image;
|
||||||
|
case CursorSource::Decoration:
|
||||||
|
return m_decorationCursor.image;
|
||||||
|
case CursorSource::Fallback:
|
||||||
|
return m_fallbackCursor.image;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint CursorImage::hotSpot() const
|
||||||
|
{
|
||||||
|
switch (m_currentSource) {
|
||||||
|
case CursorSource::EffectsOverride:
|
||||||
|
return m_effectsCursor.hotSpot;
|
||||||
|
case CursorSource::LockScreen:
|
||||||
|
case CursorSource::PointerSurface:
|
||||||
|
// lockscreen also uses server cursor image
|
||||||
|
return m_serverCursor.hotSpot;
|
||||||
|
case CursorSource::Decoration:
|
||||||
|
return m_decorationCursor.hotSpot;
|
||||||
|
case CursorSource::Fallback:
|
||||||
|
return m_fallbackCursor.hotSpot;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
|
@ -31,8 +32,10 @@ class QWindow;
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class CursorImage;
|
||||||
class InputRedirection;
|
class InputRedirection;
|
||||||
class Toplevel;
|
class Toplevel;
|
||||||
|
class WaylandCursorTheme;
|
||||||
|
|
||||||
namespace Decoration
|
namespace Decoration
|
||||||
{
|
{
|
||||||
|
@ -69,7 +72,11 @@ public:
|
||||||
return m_internalWindow;
|
return m_internalWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void installCursorFromDecoration();
|
QImage cursorImage() const;
|
||||||
|
QPoint cursorHotSpot() const;
|
||||||
|
void markCursorAsRendered();
|
||||||
|
void setEffectsOverrideCursor(Qt::CursorShape shape);
|
||||||
|
void removeEffectsOverrideCursor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -84,12 +91,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time);
|
void processAxis(InputRedirection::PointerAxis axis, qreal delta, uint32_t time);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void decorationChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updatePosition(const QPointF &pos);
|
void updatePosition(const QPointF &pos);
|
||||||
void updateButton(uint32_t button, InputRedirection::PointerButtonState state);
|
void updateButton(uint32_t button, InputRedirection::PointerButtonState state);
|
||||||
void updateInternalWindow();
|
void updateInternalWindow();
|
||||||
void updateDecoration(Toplevel *t);
|
void updateDecoration(Toplevel *t);
|
||||||
InputRedirection *m_input;
|
InputRedirection *m_input;
|
||||||
|
CursorImage *m_cursor;
|
||||||
bool m_inited = false;
|
bool m_inited = false;
|
||||||
bool m_supportsWarping;
|
bool m_supportsWarping;
|
||||||
QPointF m_pos;
|
QPointF m_pos;
|
||||||
|
@ -109,6 +120,62 @@ private:
|
||||||
QMetaObject::Connection m_internalWindowConnection;
|
QMetaObject::Connection m_internalWindowConnection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CursorImage : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit CursorImage(PointerInputRedirection *parent = nullptr);
|
||||||
|
virtual ~CursorImage();
|
||||||
|
|
||||||
|
void setEffectsOverrideCursor(Qt::CursorShape shape);
|
||||||
|
void removeEffectsOverrideCursor();
|
||||||
|
|
||||||
|
QImage image() const;
|
||||||
|
QPoint hotSpot() const;
|
||||||
|
void markAsRendered();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void changed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reevaluteSource();
|
||||||
|
void update();
|
||||||
|
void updateServerCursor();
|
||||||
|
void updateDecoration();
|
||||||
|
void updateDecorationCursor();
|
||||||
|
void loadTheme();
|
||||||
|
struct Image {
|
||||||
|
QImage image;
|
||||||
|
QPoint hotSpot;
|
||||||
|
};
|
||||||
|
void loadThemeCursor(Qt::CursorShape shape, Image *image);
|
||||||
|
|
||||||
|
enum class CursorSource {
|
||||||
|
LockScreen,
|
||||||
|
EffectsOverride,
|
||||||
|
PointerSurface,
|
||||||
|
Decoration,
|
||||||
|
Fallback
|
||||||
|
};
|
||||||
|
void setSource(CursorSource source);
|
||||||
|
|
||||||
|
PointerInputRedirection *m_pointer;
|
||||||
|
CursorSource m_currentSource = CursorSource::Fallback;
|
||||||
|
WaylandCursorTheme *m_cursorTheme = nullptr;
|
||||||
|
struct {
|
||||||
|
QMetaObject::Connection connection;
|
||||||
|
QImage image;
|
||||||
|
QPoint hotSpot;
|
||||||
|
} m_serverCursor;
|
||||||
|
|
||||||
|
Image m_effectsCursor;
|
||||||
|
Image m_decorationCursor;
|
||||||
|
QMetaObject::Connection m_decorationConnection;
|
||||||
|
Image m_fallbackCursor;
|
||||||
|
QHash<Qt::CursorShape, Image> m_cursors;
|
||||||
|
QElapsedTimer m_surfaceRenderedTimer;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue