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
icc-effect-5.14.5
Sebastian Kügler 2016-03-10 19:57:07 +01:00
parent 93ec3d84e1
commit d8a3e0525f
6 changed files with 151 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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