First part of outputmanagement wayland interface
This patch implements read access to the outputmanagement interface in kwin_wayland's drm backend. - outputdevices are created in DrmOutput, just like the wl_outputs - wayland_server implements the outputmanagement interface and - passes the changesets down into the backend This means that the interface is announced, independently of the DRM backend, but the actual outputs are currently only there if the DRM backend is used. The changes are not applied (passed into the kernel's drm interface yet). This is obviously work-in-progress, so it's incomplete. Since it allows us to run kwin[master] with the libkscreen KWayland backend, it's a significant step allowing testing and further development. Reviewed-by: Martin Gräßlin
This commit is contained in:
parent
93ec3d84e1
commit
d8a3e0525f
6 changed files with 151 additions and 0 deletions
|
@ -67,6 +67,12 @@ QPainterBackend *AbstractBackend::createQPainterBackend()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void AbstractBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config)
|
||||
{
|
||||
Q_UNUSED(config)
|
||||
qCWarning(KWIN_CORE) << "This backend does not support configuration changes.";
|
||||
}
|
||||
|
||||
void AbstractBackend::setSoftWareCursor(bool set)
|
||||
{
|
||||
if (m_softWareCursor == set) {
|
||||
|
|
|
@ -25,6 +25,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QImage>
|
||||
#include <QObject>
|
||||
|
||||
namespace KWayland {
|
||||
namespace Server {
|
||||
class OutputConfigurationInterface;
|
||||
}
|
||||
}
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -72,6 +78,14 @@ public:
|
|||
* Base implementation returns one QRect positioned at 0/0 with screenSize() as size.
|
||||
**/
|
||||
virtual QVector<QRect> screenGeometries() const;
|
||||
/**
|
||||
* Implement this method to receive configuration change requests through KWayland's
|
||||
* OutputManagement interface.
|
||||
*
|
||||
* Base implementation warns that the current backend does not implement this
|
||||
* functionality.
|
||||
*/
|
||||
virtual void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config);
|
||||
|
||||
bool usesSoftwareCursor() const {
|
||||
return m_softWareCursor;
|
||||
|
|
|
@ -33,6 +33,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// KWayland
|
||||
#include <KWayland/Server/display.h>
|
||||
#include <KWayland/Server/output_interface.h>
|
||||
#include <KWayland/Server/outputchangeset.h>
|
||||
#include <KWayland/Server/outputdevice_interface.h>
|
||||
#include <KWayland/Server/outputmanagement_interface.h>
|
||||
#include <KWayland/Server/outputconfiguration_interface.h>
|
||||
// KF5
|
||||
#include <KConfigGroup>
|
||||
#include <KLocalizedString>
|
||||
|
@ -463,6 +467,22 @@ QByteArray DrmBackend::generateOutputConfigurationUuid() const
|
|||
return hash.result().toHex().left(10);
|
||||
}
|
||||
|
||||
void DrmBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config)
|
||||
{
|
||||
const auto changes = config->changes();
|
||||
for (auto it = changes.begin(); it != changes.end(); it++) {
|
||||
|
||||
KWayland::Server::OutputChangeSet *changeset = it.value();
|
||||
|
||||
auto drmoutput = findOutput(it.key()->uuid());
|
||||
if (drmoutput == nullptr) {
|
||||
qCWarning(KWIN_DRM) << "Could NOT find DrmOutput matching " << it.key()->uuid();
|
||||
return;
|
||||
}
|
||||
drmoutput->setChanges(changeset);
|
||||
}
|
||||
}
|
||||
|
||||
DrmOutput *DrmBackend::findOutput(quint32 connector)
|
||||
{
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) {
|
||||
|
@ -474,6 +494,17 @@ DrmOutput *DrmBackend::findOutput(quint32 connector)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
DrmOutput *DrmBackend::findOutput(const QByteArray &uuid)
|
||||
{
|
||||
auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (DrmOutput *o) {
|
||||
return o->m_uuid == uuid;
|
||||
});
|
||||
if (it != m_outputs.constEnd()) {
|
||||
return *it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
quint32 DrmBackend::findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok)
|
||||
{
|
||||
if (ok) {
|
||||
|
@ -670,6 +701,7 @@ DrmOutput::~DrmOutput()
|
|||
hideCursor();
|
||||
cleanupBlackBuffer();
|
||||
delete m_waylandOutput.data();
|
||||
delete m_waylandOutputDevice.data();
|
||||
}
|
||||
|
||||
void DrmOutput::hideCursor()
|
||||
|
@ -803,11 +835,20 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
m_waylandOutput.clear();
|
||||
}
|
||||
m_waylandOutput = waylandServer()->display()->createOutput();
|
||||
if (!m_waylandOutputDevice.isNull()) {
|
||||
delete m_waylandOutputDevice.data();
|
||||
m_waylandOutputDevice.clear();
|
||||
}
|
||||
m_waylandOutputDevice = waylandServer()->display()->createOutputDevice();
|
||||
m_waylandOutputDevice->setUuid(m_uuid);
|
||||
|
||||
if (!m_edid.eisaId.isEmpty()) {
|
||||
m_waylandOutput->setManufacturer(QString::fromLatin1(m_edid.eisaId));
|
||||
} else {
|
||||
m_waylandOutput->setManufacturer(i18n("unknown"));
|
||||
}
|
||||
m_waylandOutputDevice->setManufacturer(m_waylandOutput->manufacturer());
|
||||
|
||||
if (!m_edid.monitorName.isEmpty()) {
|
||||
QString model = QString::fromLatin1(m_edid.monitorName);
|
||||
if (!m_edid.serialNumber.isEmpty()) {
|
||||
|
@ -820,6 +861,7 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
} else {
|
||||
m_waylandOutput->setModel(i18n("unknown"));
|
||||
}
|
||||
m_waylandOutputDevice->setModel(m_waylandOutput->model());
|
||||
|
||||
QSize physicalSize = !m_edid.physicalSize.isEmpty() ? m_edid.physicalSize : QSize(connector->mmWidth, connector->mmHeight);
|
||||
// the size might be completely borked. E.g. Samsung SyncMaster 2494HS reports 160x90 while in truth it's 520x292
|
||||
|
@ -834,16 +876,20 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
physicalSize = overwriteSize;
|
||||
}
|
||||
m_waylandOutput->setPhysicalSize(physicalSize);
|
||||
m_waylandOutputDevice->setPhysicalSize(physicalSize);
|
||||
|
||||
// read in mode information
|
||||
for (int i = 0; i < connector->count_modes; ++i) {
|
||||
auto *m = &connector->modes[i];
|
||||
KWayland::Server::OutputInterface::ModeFlags flags;
|
||||
KWayland::Server::OutputDeviceInterface::ModeFlags deviceflags;
|
||||
if (isCurrentMode(m)) {
|
||||
flags |= KWayland::Server::OutputInterface::ModeFlag::Current;
|
||||
deviceflags |= KWayland::Server::OutputDeviceInterface::ModeFlag::Current;
|
||||
}
|
||||
if (m->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
flags |= KWayland::Server::OutputInterface::ModeFlag::Preferred;
|
||||
deviceflags |= KWayland::Server::OutputDeviceInterface::ModeFlag::Preferred;
|
||||
}
|
||||
|
||||
// Calculate higher precision (mHz) refresh rate
|
||||
|
@ -859,6 +905,14 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
refreshRate /= m->vscan;
|
||||
}
|
||||
m_waylandOutput->addMode(QSize(m->hdisplay, m->vdisplay), flags, refreshRate);
|
||||
|
||||
KWayland::Server::OutputDeviceInterface::Mode mode;
|
||||
mode.id = i;
|
||||
mode.size = QSize(m->hdisplay, m->vdisplay);
|
||||
mode.flags = deviceflags;
|
||||
mode.refreshRate = refreshRate;
|
||||
qCDebug(KWIN_DRM) << "Adding mode: " << i << mode.size;
|
||||
m_waylandOutputDevice->addMode(mode);
|
||||
}
|
||||
|
||||
// set dpms
|
||||
|
@ -873,6 +927,8 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
}
|
||||
|
||||
m_waylandOutput->create();
|
||||
qCDebug(KWIN_DRM) << "Created OutputDevice";
|
||||
m_waylandOutputDevice->create();
|
||||
}
|
||||
|
||||
void DrmOutput::initUuid()
|
||||
|
@ -1149,6 +1205,55 @@ void DrmOutput::setGlobalPos(const QPoint &pos)
|
|||
if (m_waylandOutput) {
|
||||
m_waylandOutput->setGlobalPosition(pos);
|
||||
}
|
||||
if (m_waylandOutputDevice) {
|
||||
m_waylandOutputDevice->setGlobalPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void DrmOutput::setChanges(KWayland::Server::OutputChangeSet *changes)
|
||||
{
|
||||
m_changeset = changes;
|
||||
qCDebug(KWIN_DRM) << "set changes in DrmOutput";
|
||||
commitChanges();
|
||||
}
|
||||
|
||||
bool DrmOutput::commitChanges()
|
||||
{
|
||||
Q_ASSERT(!m_waylandOutputDevice.isNull());
|
||||
Q_ASSERT(!m_waylandOutput.isNull());
|
||||
|
||||
if (m_changeset.isNull()) {
|
||||
qCDebug(KWIN_DRM) << "no changes";
|
||||
// No changes to an output is an entirely valid thing
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_changeset->enabledChanged()) {
|
||||
qCDebug(KWIN_DRM) << "Setting enabled:";
|
||||
m_waylandOutputDevice->setEnabled(m_changeset->enabled());
|
||||
// FIXME: implement
|
||||
}
|
||||
if (m_changeset->modeChanged()) {
|
||||
qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode();
|
||||
m_waylandOutputDevice->setCurrentMode(m_changeset->mode());
|
||||
// FIXME: implement for wl_output
|
||||
}
|
||||
if (m_changeset->transformChanged()) {
|
||||
qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(m_changeset->transform());
|
||||
m_waylandOutputDevice->setTransform(m_changeset->transform());
|
||||
// FIXME: implement for wl_output
|
||||
}
|
||||
if (m_changeset->positionChanged()) {
|
||||
qCDebug(KWIN_DRM) << "Server setting position: " << m_changeset->position();
|
||||
m_waylandOutput->setGlobalPosition(m_changeset->position());
|
||||
m_waylandOutputDevice->setGlobalPosition(m_changeset->position());
|
||||
}
|
||||
if (m_changeset->scaleChanged()) {
|
||||
qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale();
|
||||
m_waylandOutputDevice->setScale(m_changeset->scale());
|
||||
// FIXME: implement for wl_output
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DrmBuffer::DrmBuffer(DrmBackend *backend, const QSize &size)
|
||||
|
|
|
@ -36,6 +36,9 @@ namespace KWayland
|
|||
namespace Server
|
||||
{
|
||||
class OutputInterface;
|
||||
class OutputDeviceInterface;
|
||||
class OutputChangeSet;
|
||||
class OutputManagementInterface;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +71,7 @@ public:
|
|||
explicit DrmBackend(QObject *parent = nullptr);
|
||||
virtual ~DrmBackend();
|
||||
|
||||
void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) override;
|
||||
Screens *createScreens(QObject *parent = nullptr) override;
|
||||
QPainterBackend *createQPainterBackend() override;
|
||||
OpenGLBackend* createOpenGLBackend() override;
|
||||
|
@ -118,6 +122,7 @@ private:
|
|||
void readOutputsConfiguration();
|
||||
QByteArray generateOutputConfigurationUuid() const;
|
||||
DrmOutput *findOutput(quint32 connector);
|
||||
DrmOutput *findOutput(const QByteArray &uuid);
|
||||
QScopedPointer<Udev> m_udev;
|
||||
QScopedPointer<UdevMonitor> m_udevMonitor;
|
||||
int m_fd = -1;
|
||||
|
@ -129,6 +134,7 @@ private:
|
|||
bool m_active = false;
|
||||
QVector<DrmBuffer*> m_buffers;
|
||||
QScopedPointer<DpmsInputEventFilter> m_dpmsFilter;
|
||||
KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr;
|
||||
};
|
||||
|
||||
class DrmOutput : public QObject
|
||||
|
@ -151,6 +157,12 @@ public:
|
|||
void restoreSaved();
|
||||
void blank();
|
||||
|
||||
/**
|
||||
* This sets the changes and tests them against the DRM output
|
||||
*/
|
||||
void setChanges(KWayland::Server::OutputChangeSet *changeset);
|
||||
bool commitChanges();
|
||||
|
||||
QSize size() const;
|
||||
QRect geometry() const;
|
||||
QString name() const;
|
||||
|
@ -201,6 +213,8 @@ private:
|
|||
Edid m_edid;
|
||||
QScopedPointer<_drmModeCrtc, CrtcCleanup> m_savedCrtc;
|
||||
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
|
||||
QPointer<KWayland::Server::OutputDeviceInterface> m_waylandOutputDevice;
|
||||
QPointer<KWayland::Server::OutputChangeSet> m_changeset;
|
||||
ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms;
|
||||
DpmsMode m_dpmsMode = DpmsMode::On;
|
||||
QByteArray m_uuid;
|
||||
|
|
|
@ -46,6 +46,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <KWayland/Server/shadow_interface.h>
|
||||
#include <KWayland/Server/blur_interface.h>
|
||||
#include <KWayland/Server/shell_interface.h>
|
||||
#include <KWayland/Server/outputmanagement_interface.h>
|
||||
#include <KWayland/Server/outputconfiguration_interface.h>
|
||||
|
||||
// Qt
|
||||
#include <QThread>
|
||||
|
@ -231,6 +233,12 @@ void WaylandServer::init(const QByteArray &socketName, InitalizationFlags flags)
|
|||
}
|
||||
);
|
||||
m_decorationManager->create();
|
||||
|
||||
m_outputManagement = m_display->createOutputManagement(m_display);
|
||||
connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested,
|
||||
this, [this](KWayland::Server::OutputConfigurationInterface *config) {
|
||||
m_backend->configurationChangeRequested(config);
|
||||
});
|
||||
}
|
||||
|
||||
void WaylandServer::initWorkspace()
|
||||
|
|
|
@ -49,6 +49,8 @@ class OutputInterface;
|
|||
class PlasmaShellInterface;
|
||||
class PlasmaWindowManagementInterface;
|
||||
class QtSurfaceExtensionInterface;
|
||||
class OutputManagementInterface;
|
||||
class OutputConfigurationInterface;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,6 +164,7 @@ Q_SIGNALS:
|
|||
private:
|
||||
quint16 createClientId(KWayland::Server::ClientConnection *c);
|
||||
void destroyInternalConnection();
|
||||
void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config);
|
||||
KWayland::Server::Display *m_display = nullptr;
|
||||
KWayland::Server::CompositorInterface *m_compositor = nullptr;
|
||||
KWayland::Server::SeatInterface *m_seat = nullptr;
|
||||
|
@ -170,6 +173,7 @@ private:
|
|||
KWayland::Server::PlasmaWindowManagementInterface *m_windowManagement = nullptr;
|
||||
KWayland::Server::QtSurfaceExtensionInterface *m_qtExtendedSurface = nullptr;
|
||||
KWayland::Server::ServerSideDecorationManagerInterface *m_decorationManager = nullptr;
|
||||
KWayland::Server::OutputManagementInterface *m_outputManagement = nullptr;
|
||||
struct {
|
||||
KWayland::Server::ClientConnection *client = nullptr;
|
||||
QMetaObject::Connection destroyConnection;
|
||||
|
|
Loading…
Reference in a new issue