[drm] Support configuring absolute output position
Begin of proper multiscreen support! We load configuration sets for the connected outputs. Each set of screens represents a unique configuration. For that we use the md5 sum of the edid+connector as uuid of an output. Each of the md5 sums is then used to create a uuid of the output set. We can be quite certain that this will generate unique ids for the use cases we will face. The uuids are used as group names. And from there we read the global position. The uuids are considered internal information. It is not intended for users to configure manually in the config file. The intended way to configure will be the OutputManagementInterface which recently got added to KWayland. Once KWin applies a configuration it will store it to config so that it can be loaded on next startup. The configuration looks like: [DrmOutputs][abcdef0123][0123abcdef] Position=0,0 [DrmOutputs][abcdef0123][fbca3bcdef] Position=1280,0 This is an example for two outputs set next to each other. Reviewed-By: Sebastian Kügler
This commit is contained in:
parent
a8ff9d39a7
commit
cbbd684430
2 changed files with 65 additions and 1 deletions
|
@ -39,6 +39,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <KLocalizedString>
|
||||
#include <KSharedConfig>
|
||||
// Qt
|
||||
#include <QCryptographicHash>
|
||||
#include <QSocketNotifier>
|
||||
#include <QPainter>
|
||||
// system
|
||||
|
@ -285,8 +286,10 @@ void DrmBackend::queryResources()
|
|||
}
|
||||
drmOutput->m_connector = connector->connector_id;
|
||||
drmOutput->init(connector.data());
|
||||
qCDebug(KWIN_DRM) << "Found new output with uuid" << drmOutput->uuid();
|
||||
connectedOutputs << drmOutput;
|
||||
}
|
||||
std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_connector < b->m_connector; });
|
||||
// check for outputs which got removed
|
||||
auto it = m_outputs.begin();
|
||||
while (it != m_outputs.end()) {
|
||||
|
@ -305,8 +308,41 @@ void DrmBackend::queryResources()
|
|||
}
|
||||
}
|
||||
m_outputs = connectedOutputs;
|
||||
readOutputsConfiguration();
|
||||
emit screensQueried();
|
||||
// TODO: install global space
|
||||
}
|
||||
|
||||
void DrmBackend::readOutputsConfiguration()
|
||||
{
|
||||
if (m_outputs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const QByteArray uuid = generateOutputConfigurationUuid();
|
||||
const auto outputGroup = KSharedConfig::openConfig(KWIN_CONFIG)->group("DrmOutputs");
|
||||
const auto configGroup = outputGroup.group(uuid);
|
||||
qCDebug(KWIN_DRM) << "Reading output configuration for" << uuid;
|
||||
// default position goes from left to right
|
||||
QPoint pos(0, 0);
|
||||
for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) {
|
||||
const auto outputConfig = configGroup.group((*it)->uuid());
|
||||
(*it)->setGlobalPos(outputConfig.readEntry<QPoint>("Position", pos));
|
||||
// TODO: add mode
|
||||
pos.setX(pos.x() + (*it)->size().width());
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray DrmBackend::generateOutputConfigurationUuid() const
|
||||
{
|
||||
auto it = m_outputs.constBegin();
|
||||
if (m_outputs.size() == 1) {
|
||||
// special case: one output
|
||||
return (*it)->uuid();
|
||||
}
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
for (; it != m_outputs.constEnd(); ++it) {
|
||||
hash.addData((*it)->uuid());
|
||||
}
|
||||
return hash.result().toHex().left(10);
|
||||
}
|
||||
|
||||
DrmOutput *DrmBackend::findOutput(quint32 connector)
|
||||
|
@ -650,6 +686,7 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
{
|
||||
initEdid(connector);
|
||||
initDpms(connector);
|
||||
initUuid();
|
||||
m_savedCrtc.reset(drmModeGetCrtc(m_backend->fd(), m_crtcId));
|
||||
blank();
|
||||
setDpms(DpmsMode::On);
|
||||
|
@ -731,6 +768,16 @@ void DrmOutput::init(drmModeConnector *connector)
|
|||
m_waylandOutput->create();
|
||||
}
|
||||
|
||||
void DrmOutput::initUuid()
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
hash.addData(QByteArray::number(m_connector));
|
||||
hash.addData(m_edid.eisaId);
|
||||
hash.addData(m_edid.monitorName);
|
||||
hash.addData(m_edid.serialNumber);
|
||||
m_uuid = hash.result().toHex().left(10);
|
||||
}
|
||||
|
||||
bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const
|
||||
{
|
||||
return mode->clock == m_mode.clock
|
||||
|
@ -996,6 +1043,14 @@ int DrmOutput::currentRefreshRate() const
|
|||
return m_waylandOutput->refreshRate();
|
||||
}
|
||||
|
||||
void DrmOutput::setGlobalPos(const QPoint &pos)
|
||||
{
|
||||
m_globalPos = pos;
|
||||
if (m_waylandOutput) {
|
||||
m_waylandOutput->setGlobalPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
DrmBuffer::DrmBuffer(DrmBackend *backend, const QSize &size)
|
||||
: m_backend(backend)
|
||||
, m_size(size)
|
||||
|
|
|
@ -107,6 +107,8 @@ private:
|
|||
quint32 findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok = nullptr);
|
||||
bool crtcIsUsed(quint32 crtc);
|
||||
void outputDpmsChanged();
|
||||
void readOutputsConfiguration();
|
||||
QByteArray generateOutputConfigurationUuid() const;
|
||||
DrmOutput *findOutput(quint32 connector);
|
||||
QScopedPointer<Udev> m_udev;
|
||||
QScopedPointer<UdevMonitor> m_udevMonitor;
|
||||
|
@ -155,6 +157,10 @@ public:
|
|||
return m_dpmsMode == DpmsMode::On;
|
||||
}
|
||||
|
||||
QByteArray uuid() const {
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void dpmsChanged();
|
||||
|
||||
|
@ -167,6 +173,8 @@ private:
|
|||
void initDpms(drmModeConnector *connector);
|
||||
bool isCurrentMode(const drmModeModeInfo *mode) const;
|
||||
void reenableDpms();
|
||||
void initUuid();
|
||||
void setGlobalPos(const QPoint &pos);
|
||||
|
||||
DrmBackend *m_backend;
|
||||
QPoint m_globalPos;
|
||||
|
@ -186,6 +194,7 @@ private:
|
|||
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
|
||||
ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms;
|
||||
DpmsMode m_dpmsMode = DpmsMode::On;
|
||||
QByteArray m_uuid;
|
||||
};
|
||||
|
||||
class DrmBuffer
|
||||
|
|
Loading…
Reference in a new issue