backends/x11: Provide a cursor per output
The main motivation behind this change is to allow setting the cursor per output, which eases up implementing things such as cursor output layers. It also has another advantage - output related code is more encapsulated. Furthermore, we could decouple output backends from Cursor.
This commit is contained in:
parent
6e6caa1021
commit
7939352fb7
4 changed files with 84 additions and 52 deletions
|
@ -17,7 +17,6 @@
|
|||
#include "x11_windowed_logging.h"
|
||||
#include "x11_windowed_output.h"
|
||||
#include "x11_windowed_qpainter_backend.h"
|
||||
#include <cursor.h>
|
||||
#include <pointer_input.h>
|
||||
// KDE
|
||||
#include <KLocalizedString>
|
||||
|
@ -171,9 +170,6 @@ X11WindowedBackend::~X11WindowedBackend()
|
|||
if (m_keySymbols) {
|
||||
xcb_key_symbols_free(m_keySymbols);
|
||||
}
|
||||
if (m_cursor) {
|
||||
xcb_free_cursor(m_connection, m_cursor);
|
||||
}
|
||||
xcb_disconnect(m_connection);
|
||||
}
|
||||
}
|
||||
|
@ -203,10 +199,6 @@ bool X11WindowedBackend::initialize()
|
|||
XRenderUtils::init(m_connection, m_screen->root);
|
||||
createOutputs();
|
||||
connect(kwinApp(), &Application::workspaceCreated, this, &X11WindowedBackend::startEventReading);
|
||||
connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() {
|
||||
KWin::Cursor *c = KWin::Cursors::self()->currentCursor();
|
||||
createCursor(c->image(), c->hotspot());
|
||||
});
|
||||
m_pointerDevice = std::make_unique<X11WindowedInputDevice>();
|
||||
m_pointerDevice->setPointer(true);
|
||||
m_keyboardDevice = std::make_unique<X11WindowedInputDevice>();
|
||||
|
@ -573,48 +565,6 @@ void X11WindowedBackend::updateSize(xcb_configure_notify_event_t *event)
|
|||
Q_EMIT sizeChanged();
|
||||
}
|
||||
|
||||
void X11WindowedBackend::createCursor(const QImage &srcImage, const QPoint &hotspot)
|
||||
{
|
||||
xcb_pixmap_t pix = XCB_PIXMAP_NONE;
|
||||
xcb_gcontext_t gc = XCB_NONE;
|
||||
xcb_cursor_t cid = XCB_CURSOR_NONE;
|
||||
|
||||
if (!srcImage.isNull()) {
|
||||
pix = xcb_generate_id(m_connection);
|
||||
gc = xcb_generate_id(m_connection);
|
||||
cid = xcb_generate_id(m_connection);
|
||||
|
||||
// right now on X we only have one scale between all screens, and we know we will have at least one screen
|
||||
const qreal outputScale = 1;
|
||||
const QSize targetSize = srcImage.size() * outputScale / srcImage.devicePixelRatio();
|
||||
const QImage img = srcImage.scaled(targetSize, Qt::KeepAspectRatio);
|
||||
|
||||
xcb_create_pixmap(m_connection, 32, pix, m_screen->root, img.width(), img.height());
|
||||
xcb_create_gc(m_connection, gc, pix, 0, nullptr);
|
||||
|
||||
xcb_put_image(m_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc, img.width(), img.height(), 0, 0, 0, 32, img.sizeInBytes(), img.constBits());
|
||||
|
||||
XRenderPicture pic(pix, 32);
|
||||
xcb_render_create_cursor(m_connection, cid, pic, qRound(hotspot.x() * outputScale), qRound(hotspot.y() * outputScale));
|
||||
}
|
||||
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
xcb_change_window_attributes(m_connection, (*it)->window(), XCB_CW_CURSOR, &cid);
|
||||
}
|
||||
|
||||
if (pix) {
|
||||
xcb_free_pixmap(m_connection, pix);
|
||||
}
|
||||
if (gc) {
|
||||
xcb_free_gc(m_connection, gc);
|
||||
}
|
||||
if (m_cursor) {
|
||||
xcb_free_cursor(m_connection, m_cursor);
|
||||
}
|
||||
m_cursor = cid;
|
||||
xcb_flush(m_connection);
|
||||
}
|
||||
|
||||
xcb_window_t X11WindowedBackend::rootWindow() const
|
||||
{
|
||||
if (!m_screen) {
|
||||
|
|
|
@ -150,7 +150,6 @@ private:
|
|||
void handleButtonPress(xcb_button_press_event_t *event);
|
||||
void handleExpose(xcb_expose_event_t *event);
|
||||
void updateSize(xcb_configure_notify_event_t *event);
|
||||
void createCursor(const QImage &img, const QPoint &hotspot);
|
||||
void initXInput();
|
||||
X11WindowedOutput *findOutput(xcb_window_t window) const;
|
||||
|
||||
|
@ -166,7 +165,6 @@ private:
|
|||
|
||||
xcb_atom_t m_protocols = XCB_ATOM_NONE;
|
||||
xcb_atom_t m_deleteWindowProtocol = XCB_ATOM_NONE;
|
||||
xcb_cursor_t m_cursor = XCB_CURSOR_NONE;
|
||||
Display *m_display = nullptr;
|
||||
bool m_keyboardGrabbed = false;
|
||||
std::unique_ptr<QSocketNotifier> m_eventNotifier;
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "x11_windowed_output.h"
|
||||
#include "../common/kwinxrenderutils.h"
|
||||
|
||||
#include <config-kwin.h>
|
||||
|
||||
#include "core/renderloop_p.h"
|
||||
#include "cursor.h"
|
||||
#include "softwarevsyncmonitor.h"
|
||||
#include "x11_windowed_backend.h"
|
||||
|
||||
|
@ -25,6 +27,63 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
X11WindowedCursor::X11WindowedCursor(X11WindowedOutput *output)
|
||||
: m_output(output)
|
||||
{
|
||||
}
|
||||
|
||||
X11WindowedCursor::~X11WindowedCursor()
|
||||
{
|
||||
if (m_handle != XCB_CURSOR_NONE) {
|
||||
xcb_free_cursor(m_output->backend()->connection(), m_handle);
|
||||
m_handle = XCB_CURSOR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void X11WindowedCursor::update(const QImage &image, const QPoint &hotspot)
|
||||
{
|
||||
X11WindowedBackend *backend = m_output->backend();
|
||||
|
||||
xcb_connection_t *connection = backend->connection();
|
||||
xcb_pixmap_t pix = XCB_PIXMAP_NONE;
|
||||
xcb_gcontext_t gc = XCB_NONE;
|
||||
xcb_cursor_t cid = XCB_CURSOR_NONE;
|
||||
|
||||
if (!image.isNull()) {
|
||||
pix = xcb_generate_id(connection);
|
||||
gc = xcb_generate_id(connection);
|
||||
cid = xcb_generate_id(connection);
|
||||
|
||||
// right now on X we only have one scale between all screens, and we know we will have at least one screen
|
||||
const qreal outputScale = 1;
|
||||
const QSize targetSize = image.size() * outputScale / image.devicePixelRatio();
|
||||
const QImage img = image.scaled(targetSize, Qt::KeepAspectRatio);
|
||||
|
||||
xcb_create_pixmap(connection, 32, pix, backend->screen()->root, img.width(), img.height());
|
||||
xcb_create_gc(connection, gc, pix, 0, nullptr);
|
||||
|
||||
xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc, img.width(), img.height(), 0, 0, 0, 32, img.sizeInBytes(), img.constBits());
|
||||
|
||||
XRenderPicture pic(pix, 32);
|
||||
xcb_render_create_cursor(connection, cid, pic, qRound(hotspot.x() * outputScale), qRound(hotspot.y() * outputScale));
|
||||
}
|
||||
|
||||
xcb_change_window_attributes(connection, m_output->window(), XCB_CW_CURSOR, &cid);
|
||||
|
||||
if (pix) {
|
||||
xcb_free_pixmap(connection, pix);
|
||||
}
|
||||
if (gc) {
|
||||
xcb_free_gc(connection, gc);
|
||||
}
|
||||
|
||||
if (m_handle) {
|
||||
xcb_free_cursor(connection, m_handle);
|
||||
}
|
||||
m_handle = cid;
|
||||
xcb_flush(connection);
|
||||
}
|
||||
|
||||
X11WindowedOutput::X11WindowedOutput(X11WindowedBackend *backend)
|
||||
: Output(backend)
|
||||
, m_renderLoop(std::make_unique<RenderLoop>())
|
||||
|
@ -138,6 +197,12 @@ void X11WindowedOutput::init(const QSize &pixelSize, qreal scale)
|
|||
addIcon(QSize(32, 32));
|
||||
addIcon(QSize(48, 48));
|
||||
|
||||
m_cursor = std::make_unique<X11WindowedCursor>(this);
|
||||
connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() {
|
||||
KWin::Cursor *c = KWin::Cursors::self()->currentCursor();
|
||||
m_cursor->update(c->image(), c->hotspot());
|
||||
});
|
||||
|
||||
xcb_map_window(m_backend->connection(), m_window);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,20 @@ namespace KWin
|
|||
|
||||
class SoftwareVsyncMonitor;
|
||||
class X11WindowedBackend;
|
||||
class X11WindowedOutput;
|
||||
|
||||
class X11WindowedCursor
|
||||
{
|
||||
public:
|
||||
explicit X11WindowedCursor(X11WindowedOutput *output);
|
||||
~X11WindowedCursor();
|
||||
|
||||
void update(const QImage &image, const QPoint &hotspot);
|
||||
|
||||
private:
|
||||
X11WindowedOutput *m_output;
|
||||
xcb_cursor_t m_handle = XCB_CURSOR_NONE;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wayland outputs in a nested X11 setup
|
||||
|
@ -41,6 +55,10 @@ public:
|
|||
void init(const QSize &pixelSize, qreal scale);
|
||||
void resize(const QSize &pixelSize);
|
||||
|
||||
X11WindowedBackend *backend() const
|
||||
{
|
||||
return m_backend;
|
||||
}
|
||||
xcb_window_t window() const
|
||||
{
|
||||
return m_window;
|
||||
|
@ -76,6 +94,7 @@ private:
|
|||
std::unique_ptr<NETWinInfo> m_winInfo;
|
||||
std::unique_ptr<RenderLoop> m_renderLoop;
|
||||
std::unique_ptr<SoftwareVsyncMonitor> m_vsyncMonitor;
|
||||
std::unique_ptr<X11WindowedCursor> m_cursor;
|
||||
QPoint m_hostPosition;
|
||||
QRegion m_exposedArea;
|
||||
|
||||
|
|
Loading…
Reference in a new issue