[wayland] Set internal cursor through WaylandCursorTheme in AbstractBackend
Getting the cursor image from the cursor theme is unfortunately not straight forward. We have three different libraries and all have drawbacks: * XCursor - we just kicked it out * xcb-util/cursor - only provides xcb_cursor_t, so a dependency on X * wayland-cursor - only a client side API The picked solution is using wayland-cursor. It provides the cursor in a wl_buffer. Unfortunately the client side API does not easily allow to a) read it back b) init without a wl_shm_pool Thus we need to work this around: * create an internal connection * get a ShmPool on it * init WaylandCursorTheme with this ShmPool * get the cursor wl_buffer from the theme * trigger a roundtrip * get the corresponding BufferInterface for the buffer * set the content as the software cursoricc-effect-5.14.5
parent
265af8e7ed
commit
2b185fa7e0
|
@ -18,13 +18,24 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "abstract_backend.h"
|
||||
#include <config-kwin.h>
|
||||
#include "composite.h"
|
||||
#include "cursor.h"
|
||||
#include "wayland_server.h"
|
||||
#if HAVE_WAYLAND_CURSOR
|
||||
#include "wayland_backend.h"
|
||||
#endif
|
||||
// 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
|
||||
#if HAVE_WAYLAND_CURSOR
|
||||
#include <wayland-cursor.h>
|
||||
#endif
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -67,7 +78,47 @@ void AbstractBackend::installCursorFromServer()
|
|||
|
||||
void AbstractBackend::installCursorImage(Qt::CursorShape shape)
|
||||
{
|
||||
if (!m_softWareCursor) {
|
||||
return;
|
||||
}
|
||||
#if HAVE_WAYLAND_CURSOR
|
||||
if (!m_cursorTheme) {
|
||||
// check whether we can create it
|
||||
if (waylandServer() && waylandServer()->internalShmPool()) {
|
||||
m_cursorTheme = new Wayland::WaylandCursorTheme(waylandServer()->internalShmPool(), this);
|
||||
}
|
||||
}
|
||||
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();
|
||||
QMetaObject::invokeMethod(this,
|
||||
"installThemeCursor",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(quint32, KWayland::Client::Buffer::getId(b)),
|
||||
Q_ARG(QPoint, QPoint(cursor->hotspot_x, cursor->hotspot_y)));
|
||||
#else
|
||||
Q_UNUSED(shape)
|
||||
#endif
|
||||
}
|
||||
|
||||
void AbstractBackend::installThemeCursor(quint32 id, const QPoint &hotspot)
|
||||
{
|
||||
auto buffer = KWayland::Server::BufferInterface::get(waylandServer()->internalConnection()->getResource(id));
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
triggerCursorRepaint();
|
||||
m_cursor.hotspot = hotspot;
|
||||
m_cursor.image = buffer->data().copy();
|
||||
}
|
||||
|
||||
Screens *AbstractBackend::createScreens(QObject *parent)
|
||||
|
|
|
@ -30,6 +30,11 @@ class OpenGLBackend;
|
|||
class QPainterBackend;
|
||||
class Screens;
|
||||
|
||||
namespace Wayland
|
||||
{
|
||||
class WaylandCursorTheme;
|
||||
}
|
||||
|
||||
class KWIN_EXPORT AbstractBackend : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -57,6 +62,9 @@ protected:
|
|||
explicit AbstractBackend(QObject *parent = nullptr);
|
||||
void setSoftWareCursor(bool set);
|
||||
|
||||
private Q_SLOTS:
|
||||
void installThemeCursor(quint32 id, const QPoint &hotspot);
|
||||
|
||||
private:
|
||||
void triggerCursorRepaint();
|
||||
bool m_softWareCursor = false;
|
||||
|
@ -65,6 +73,7 @@ private:
|
|||
QImage image;
|
||||
QPoint lastRenderedPosition;
|
||||
} m_cursor;
|
||||
Wayland::WaylandCursorTheme *m_cursorTheme = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ void ApplicationWayland::performStartup()
|
|||
setOperationMode(m_startXWayland ? OperationModeXwayland : OperationModeWaylandAndX11);
|
||||
// first load options - done internally by a different thread
|
||||
createOptions();
|
||||
waylandServer()->createInternalConnection();
|
||||
|
||||
// try creating the Wayland Backend
|
||||
createInput();
|
||||
|
|
|
@ -22,6 +22,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "toplevel.h"
|
||||
#include "workspace.h"
|
||||
|
||||
// Client
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/registry.h>
|
||||
// Server
|
||||
#include <KWayland/Server/compositor_interface.h>
|
||||
#include <KWayland/Server/display.h>
|
||||
#include <KWayland/Server/output_interface.h>
|
||||
|
@ -113,6 +117,32 @@ int WaylandServer::createQtConnection()
|
|||
return sx[1];
|
||||
}
|
||||
|
||||
void WaylandServer::createInternalConnection()
|
||||
{
|
||||
int sx[2];
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
|
||||
qCWarning(KWIN_CORE) << "Could not create socket";
|
||||
return;
|
||||
}
|
||||
m_internalConnection.server = m_display->createClient(sx[0]);
|
||||
using namespace KWayland::Client;
|
||||
m_internalConnection.client = new ConnectionThread(this);
|
||||
m_internalConnection.client->setSocketFd(sx[1]);
|
||||
connect(m_internalConnection.client, &ConnectionThread::connected, this,
|
||||
[this] {
|
||||
Registry *registry = new Registry(m_internalConnection.client);
|
||||
registry->create(m_internalConnection.client);
|
||||
connect(registry, &Registry::shmAnnounced, this,
|
||||
[this, registry] (quint32 name, quint32 version) {
|
||||
m_internalConnection.shm = registry->createShmPool(name, version, m_internalConnection.client);
|
||||
}
|
||||
);
|
||||
registry->setup();
|
||||
}
|
||||
);
|
||||
m_internalConnection.client->initConnection();
|
||||
}
|
||||
|
||||
void WaylandServer::installBackend(AbstractBackend *backend)
|
||||
{
|
||||
Q_ASSERT(!m_backend);
|
||||
|
|
|
@ -26,6 +26,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class ConnectionThread;
|
||||
class ShmPool;
|
||||
}
|
||||
namespace Server
|
||||
{
|
||||
class ClientConnection;
|
||||
|
@ -78,10 +83,20 @@ public:
|
|||
* @returns file descriptor for QtWayland
|
||||
**/
|
||||
int createQtConnection();
|
||||
void createInternalConnection();
|
||||
|
||||
KWayland::Server::ClientConnection *xWaylandConnection() const {
|
||||
return m_xwaylandConnection;
|
||||
}
|
||||
KWayland::Server::ClientConnection *internalConnection() const {
|
||||
return m_internalConnection.server;
|
||||
}
|
||||
KWayland::Client::ShmPool *internalShmPool() {
|
||||
return m_internalConnection.shm;
|
||||
}
|
||||
KWayland::Client::ConnectionThread *internalClientConection() {
|
||||
return m_internalConnection.client;
|
||||
}
|
||||
|
||||
private:
|
||||
KWayland::Server::Display *m_display = nullptr;
|
||||
|
@ -90,6 +105,12 @@ private:
|
|||
KWayland::Server::ShellInterface *m_shell = nullptr;
|
||||
KWayland::Server::ClientConnection *m_xwaylandConnection = nullptr;
|
||||
KWayland::Server::ClientConnection *m_qtConnection = nullptr;
|
||||
struct {
|
||||
KWayland::Server::ClientConnection *server = nullptr;
|
||||
KWayland::Client::ConnectionThread *client = nullptr;
|
||||
KWayland::Client::ShmPool *shm = nullptr;
|
||||
|
||||
} m_internalConnection;
|
||||
AbstractBackend *m_backend = nullptr;
|
||||
KWIN_SINGLETON(WaylandServer)
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue