/* SPDX-FileCopyrightText: 2016 Marco Martin SPDX-License-Identifier: LGPL-2.0-or-later */ #include "screenpool.h" #include #include #include ScreenPool::ScreenPool(const KSharedConfig::Ptr &config, QObject *parent) : QObject(parent) , m_configGroup(KConfigGroup(config, QStringLiteral("ScreenConnectors"))) { m_configSaveTimer.setSingleShot(true); connect(&m_configSaveTimer, &QTimer::timeout, this, [this]() { m_configGroup.sync(); }); } void ScreenPool::load(QScreen *primary) { m_primaryConnector = QString(); m_connectorForId.clear(); m_idForConnector.clear(); if (primary) { m_primaryConnector = primary->name(); if (!m_primaryConnector.isEmpty()) { m_connectorForId[0] = m_primaryConnector; m_idForConnector[m_primaryConnector] = 0; } } // restore the known ids to connector mappings const auto keys = m_configGroup.keyList(); for (const QString &key : keys) { QString connector = m_configGroup.readEntry(key, QString()); const int currentId = key.toInt(); if (!key.isEmpty() && !connector.isEmpty() && !m_connectorForId.contains(currentId) && !m_idForConnector.contains(connector)) { m_connectorForId[currentId] = connector; m_idForConnector[connector] = currentId; } else if (m_idForConnector.value(connector) != currentId) { m_configGroup.deleteEntry(key); } } // if there are already connected unknown screens, map those // all needs to be populated as soon as possible, otherwise // containment->screen() will return an incorrect -1 // at startup, if it' asked before corona::addOutput() // is performed, driving to the creation of a new containment for (QScreen *screen : qGuiApp->screens()) { if (!m_idForConnector.contains(screen->name())) { insertScreenMapping(firstAvailableId(), screen->name()); } } } ScreenPool::~ScreenPool() { m_configGroup.sync(); } QString ScreenPool::primaryConnector() const { return m_primaryConnector; } void ScreenPool::setPrimaryConnector(const QString &primary) { if (m_primaryConnector == primary) { return; } int oldIdForPrimary = m_idForConnector.value(primary, -1); if (oldIdForPrimary == -1) { // move old primary to new free id oldIdForPrimary = firstAvailableId(); insertScreenMapping(oldIdForPrimary, m_primaryConnector); } m_idForConnector[primary] = 0; m_connectorForId[0] = primary; m_idForConnector[m_primaryConnector] = oldIdForPrimary; m_connectorForId[oldIdForPrimary] = m_primaryConnector; m_primaryConnector = primary; save(); } void ScreenPool::save() { QMap::const_iterator i; for (i = m_connectorForId.constBegin(); i != m_connectorForId.constEnd(); ++i) { m_configGroup.writeEntry(QString::number(i.key()), i.value()); } // write to disck every 30 seconds at most m_configSaveTimer.start(30000); } void ScreenPool::insertScreenMapping(int id, const QString &connector) { Q_ASSERT(!m_connectorForId.contains(id) || m_connectorForId.value(id) == connector); Q_ASSERT(!m_idForConnector.contains(connector) || m_idForConnector.value(connector) == id); if (id == 0) { m_primaryConnector = connector; } m_connectorForId[id] = connector; m_idForConnector[connector] = id; save(); } int ScreenPool::id(const QString &connector) const { return m_idForConnector.value(connector, -1); } QString ScreenPool::connector(int id) const { Q_ASSERT(m_connectorForId.contains(id)); return m_connectorForId.value(id); } int ScreenPool::firstAvailableId() const { int i = 0; // find the first integer not stored in m_connectorForId // m_connectorForId is the only map, so the ids are sorted foreach (int existingId, m_connectorForId.keys()) { if (i != existingId) { return i; } ++i; } return i; } QList ScreenPool::knownIds() const { return m_connectorForId.keys(); } #include "moc_screenpool.cpp"