[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 cursor
icc-effect-5.14.5
Martin Gräßlin 2015-04-02 14:37:23 +02:00
parent 265af8e7ed
commit 2b185fa7e0
5 changed files with 112 additions and 0 deletions

View File

@ -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)

View File

@ -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;
};
}

View File

@ -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();

View File

@ -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);

View File

@ -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)
};