diff --git a/wayland_backend.cpp b/wayland_backend.cpp index 4291c40049..03f73a486b 100644 --- a/wayland_backend.cpp +++ b/wayland_backend.cpp @@ -61,6 +61,8 @@ static void registryHandleGlobal(void *data, struct wl_registry *registry, d->createSeat(name); } else if (strcmp(interface, "wl_shm") == 0) { d->createShm(name); + } else if (strcmp(interface, "wl_output") == 0) { + d->addOutput(reinterpret_cast(wl_registry_bind(registry, name, &wl_output_interface, 1))); } qDebug() << "Wayland Interface: " << interface; } @@ -215,6 +217,48 @@ static void bufferRelease(void *data, wl_buffer *wl_buffer) buffer->setReleased(true); } +static void outputHandleGeometry(void *data, wl_output *output, int32_t x, int32_t y, + int32_t physicalWidth, int32_t physicalHeight, int32_t subPixel, + const char *make, const char *model, int32_t transform) +{ + Q_UNUSED(subPixel) + Q_UNUSED(transform) + Output *o = reinterpret_cast(data); + if (o->output() != output) { + return; + } + o->setGlobalPosition(QPoint(x, y)); + o->setManufacturer(make); + o->setModel(model); + o->setPhysicalSize(QSize(physicalWidth, physicalHeight)); + o->emitChanged(); +} + +static void outputHandleMode(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) +{ + Q_UNUSED(flags) + Output *o = reinterpret_cast(data); + if (o->output() != output) { + return; + } + o->setPixelSize(QSize(width, height)); + o->setRefreshRate(refresh); + o->emitChanged(); +} + +static void outputHandleDone(void *data, wl_output *output) +{ + Q_UNUSED(data) + Q_UNUSED(output) +} + +static void outputHandleScale(void *data, wl_output *output, int32_t scale) +{ + Q_UNUSED(data) + Q_UNUSED(output) + Q_UNUSED(scale) +} + // handlers static const struct wl_registry_listener s_registryListener = { registryHandleGlobal, @@ -251,6 +295,13 @@ static const struct wl_buffer_listener s_bufferListener = { bufferRelease }; +static const struct wl_output_listener s_outputListener = { + outputHandleGeometry, + outputHandleMode, + outputHandleDone, + outputHandleScale +}; + CursorData::CursorData() : m_valid(init()) { @@ -614,6 +665,59 @@ void WaylandSeat::destroyTheme() } } +Output::Output(wl_output *output, QObject *parent) + : QObject(parent) + , m_output(output) + , m_physicalSize() + , m_globalPosition() + , m_manufacturer() + , m_model() + , m_pixelSize() + , m_refreshRate(0) +{ + wl_output_add_listener(m_output, &s_outputListener, this); +} + +Output::~Output() +{ + wl_output_destroy(m_output); +} + +void Output::setGlobalPosition(const QPoint &pos) +{ + m_globalPosition = pos; +} + +void Output::setManufacturer(const QString &manufacturer) +{ + m_manufacturer = manufacturer; +} + +void Output::setModel(const QString &model) +{ + m_model = model; +} + +void Output::setPhysicalSize(const QSize &size) +{ + m_physicalSize = size; +} + +void Output::setPixelSize(const QSize& size) +{ + m_pixelSize = size; +} + +void Output::setRefreshRate(int refreshRate) +{ + m_refreshRate = refreshRate; +} + +void Output::emitChanged() +{ + emit changed(); +} + WaylandBackend *WaylandBackend::s_self = 0; WaylandBackend *WaylandBackend::create(QObject *parent) { @@ -652,6 +756,7 @@ WaylandBackend::WaylandBackend(QObject *parent) WaylandBackend::~WaylandBackend() { + destroyOutputs(); if (m_shellSurface) { wl_shell_surface_destroy(m_shellSurface); } @@ -675,6 +780,12 @@ WaylandBackend::~WaylandBackend() s_self = NULL; } +void WaylandBackend::destroyOutputs() +{ + qDeleteAll(m_outputs); + m_outputs.clear(); +} + void WaylandBackend::initConnection() { m_display = wl_display_connect(nullptr); @@ -717,6 +828,7 @@ void WaylandBackend::socketFileChanged(const QString &socket) emit systemCompositorDied(); m_seat.reset(); m_shm.reset(); + destroyOutputs(); if (m_shellSurface) { free(m_shellSurface); m_shellSurface = nullptr; @@ -822,6 +934,13 @@ void WaylandBackend::setShellSurfaceSize(const QSize &size) emit shellSurfaceSizeChanged(m_shellSurfaceSize); } +void WaylandBackend::addOutput(wl_output *o) +{ + Output *output = new Output(o, this); + m_outputs.append(output); + connect(output, &Output::changed, this, &WaylandBackend::outputsChanged); +} + void WaylandBackend::dispatchEvents() { wl_display_dispatch_pending(m_display); diff --git a/wayland_backend.h b/wayland_backend.h index ad8ddad14d..eee93a93ad 100644 --- a/wayland_backend.h +++ b/wayland_backend.h @@ -160,6 +160,44 @@ private: WaylandBackend *m_backend; }; +class Output : public QObject +{ + Q_OBJECT +public: + Output(wl_output *output, QObject *parent); + virtual ~Output(); + + wl_output *output(); + const QSize &physicalSize() const; + const QPoint &globalPosition() const; + const QString &manufacturer() const; + const QString &model() const; + const QSize &pixelSize() const; + QRect geometry() const; + int refreshRate() const; + + void setPhysicalSize(const QSize &size); + void setGlobalPosition(const QPoint &pos); + void setManufacturer(const QString &manufacturer); + void setModel(const QString &model); + void setPixelSize(const QSize &size); + void setRefreshRate(int refreshRate); + + void emitChanged(); + +Q_SIGNALS: + void changed(); + +private: + wl_output *m_output; + QSize m_physicalSize; + QPoint m_globalPosition; + QString m_manufacturer; + QString m_model; + QSize m_pixelSize; + int m_refreshRate; +}; + /** * @brief Class encapsulating all Wayland data structures needed by the Egl backend. * @@ -177,6 +215,8 @@ public: wl_compositor *compositor(); void setShell(wl_shell *s); wl_shell *shell(); + void addOutput(wl_output *o); + const QList &outputs() const; ShmPool *shmPool(); void createSeat(uint32_t name); void createShm(uint32_t name); @@ -192,6 +232,7 @@ Q_SIGNALS: void shellSurfaceSizeChanged(const QSize &size); void systemCompositorDied(); void backendReady(); + void outputsChanged(); private Q_SLOTS: void readEvents(); void socketFileChanged(const QString &socket); @@ -199,6 +240,7 @@ private Q_SLOTS: private: void initConnection(); void createSurface(); + void destroyOutputs(); wl_display *m_display; wl_registry *m_registry; wl_compositor *m_compositor; @@ -212,6 +254,7 @@ private: QString m_socketName; QDir m_runtimeDir; QFileSystemWatcher *m_socketWatcher; + QList m_outputs; KWIN_SINGLETON(WaylandBackend) }; @@ -258,6 +301,54 @@ wl_shm *ShmPool::shm() return m_shm; } +inline +QRect Output::geometry() const +{ + return QRect(m_globalPosition, m_pixelSize); +} + +inline +const QPoint &Output::globalPosition() const +{ + return m_globalPosition; +} + +inline +const QString &Output::manufacturer() const +{ + return m_manufacturer; +} + +inline +const QString &Output::model() const +{ + return m_model; +} + +inline +wl_output *Output::output() +{ + return m_output; +} + +inline +const QSize &Output::physicalSize() const +{ + return m_physicalSize; +} + +inline +const QSize &Output::pixelSize() const +{ + return m_pixelSize; +} + +inline +int Output::refreshRate() const +{ + return m_refreshRate; +} + inline wl_display *WaylandBackend::display() { @@ -306,6 +397,12 @@ const QSize &WaylandBackend::shellSurfaceSize() const return m_shellSurfaceSize; } +inline +const QList< Output* >& WaylandBackend::outputs() const +{ + return m_outputs; +} + inline wl_buffer* Buffer::buffer() const {