Support dynamic output enabling/disabling from KScreen
Summary: We need to keep the DrmOutput object to still have the WaylandOutputDevice. Screens currently start off enabled as before. In order to keep KWin to have a correct index based list of screens we need to store a second vector of currently enabled outputs for the screens interface. Test Plan: Had dual screens. Disabled/Enabled each one through the kscreen KCM Reviewers: #plasma, graesslin Reviewed By: #plasma, graesslin Subscribers: ngraham, luebking, broulik, graesslin, plasma-devel, kwin, #kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D8796
This commit is contained in:
parent
45ac8eed34
commit
01c1870e9d
5 changed files with 95 additions and 27 deletions
|
@ -127,7 +127,7 @@ void DrmBackend::outputWentOff()
|
|||
void DrmBackend::turnOutputsOn()
|
||||
{
|
||||
m_dpmsFilter.reset();
|
||||
for (auto it = m_outputs.constBegin(), end = m_outputs.constEnd(); it != end; it++) {
|
||||
for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) {
|
||||
(*it)->setDpms(DrmOutput::DpmsMode::On);
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ void DrmBackend::checkOutputsAreOn()
|
|||
// already disabled, all outputs are on
|
||||
return;
|
||||
}
|
||||
for (auto it = m_outputs.constBegin(), end = m_outputs.constEnd(); it != end; it++) {
|
||||
for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) {
|
||||
if (!(*it)->isDpmsEnabled()) {
|
||||
// dpms still disabled, need to keep the filter
|
||||
return;
|
||||
|
@ -396,6 +396,7 @@ void DrmBackend::updateOutputs()
|
|||
}
|
||||
DrmOutput *removed = *it;
|
||||
it = m_outputs.erase(it);
|
||||
m_enabledOutputs.removeOne(removed);
|
||||
emit outputRemoved(removed);
|
||||
delete removed;
|
||||
}
|
||||
|
@ -475,6 +476,7 @@ void DrmBackend::updateOutputs()
|
|||
}
|
||||
std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); });
|
||||
m_outputs = connectedOutputs;
|
||||
m_enabledOutputs = connectedOutputs;
|
||||
readOutputsConfiguration();
|
||||
if (!m_outputs.isEmpty()) {
|
||||
emit screensQueried();
|
||||
|
@ -518,18 +520,50 @@ QByteArray DrmBackend::generateOutputConfigurationUuid() const
|
|||
void DrmBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config)
|
||||
{
|
||||
const auto changes = config->changes();
|
||||
for (auto it = changes.begin(); it != changes.end(); it++) {
|
||||
bool countChanged = false;
|
||||
|
||||
//process all non-disabling 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;
|
||||
continue;
|
||||
}
|
||||
if (changeset->enabledChanged() && changeset->enabled() == KWayland::Server::OutputDeviceInterface::Enablement::Enabled) {
|
||||
drmoutput->setEnabled(true);
|
||||
m_enabledOutputs << drmoutput;
|
||||
emit outputAdded(drmoutput);
|
||||
countChanged = true;
|
||||
}
|
||||
drmoutput->setChanges(changeset);
|
||||
}
|
||||
emit screens()->changed();
|
||||
//process any disable requests
|
||||
for (auto it = changes.begin(); it != changes.end(); it++) {
|
||||
KWayland::Server::OutputChangeSet *changeset = it.value();
|
||||
if (changeset->enabledChanged() && changeset->enabled() == KWayland::Server::OutputDeviceInterface::Enablement::Disabled) {
|
||||
if (m_enabledOutputs.count() == 1) {
|
||||
qCWarning(KWIN_DRM) << "Not disabling final screen" << it.key()->uuid();
|
||||
continue;
|
||||
}
|
||||
auto drmoutput = findOutput(it.key()->uuid());
|
||||
if (drmoutput == nullptr) {
|
||||
qCWarning(KWIN_DRM) << "Could NOT find DrmOutput matching " << it.key()->uuid();
|
||||
continue;
|
||||
}
|
||||
drmoutput->setEnabled(false);
|
||||
m_enabledOutputs.removeOne(drmoutput);
|
||||
emit outputRemoved(drmoutput);
|
||||
countChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (countChanged) {
|
||||
emit screensQueried();
|
||||
} else {
|
||||
emit screens()->changed();
|
||||
}
|
||||
// KCoreAddons needs kwayland's 2b3f9509ac1 to not crash
|
||||
if (KCoreAddons::version() >= QT_VERSION_CHECK(5, 39, 0)) {
|
||||
config->setApplied();
|
||||
|
@ -706,11 +740,11 @@ DrmSurfaceBuffer *DrmBackend::createBuffer(const std::shared_ptr<GbmSurface> &su
|
|||
|
||||
void DrmBackend::outputDpmsChanged()
|
||||
{
|
||||
if (m_outputs.isEmpty()) {
|
||||
if (m_enabledOutputs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
bool enabled = false;
|
||||
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
|
||||
for (auto it = m_enabledOutputs.constBegin(); it != m_enabledOutputs.constEnd(); ++it) {
|
||||
enabled = enabled || (*it)->isDpmsEnabled();
|
||||
}
|
||||
setOutputsEnabled(enabled);
|
||||
|
|
|
@ -92,6 +92,9 @@ public:
|
|||
QVector<DrmOutput*> outputs() const {
|
||||
return m_outputs;
|
||||
}
|
||||
QVector<DrmOutput*> enabledOutputs() const {
|
||||
return m_enabledOutputs;
|
||||
}
|
||||
QVector<DrmPlane*> planes() const {
|
||||
return m_planes;
|
||||
}
|
||||
|
@ -126,7 +129,13 @@ public Q_SLOTS:
|
|||
void turnOutputsOn();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted whenever an output is removed/disabled
|
||||
*/
|
||||
void outputRemoved(KWin::DrmOutput *output);
|
||||
/**
|
||||
* Emitted whenever an output is added/enabled
|
||||
*/
|
||||
void outputAdded(KWin::DrmOutput *output);
|
||||
|
||||
protected:
|
||||
|
@ -158,8 +167,11 @@ private:
|
|||
QVector<DrmCrtc*> m_crtcs;
|
||||
// all connectors
|
||||
QVector<DrmConnector*> m_connectors;
|
||||
// currently active output pipelines (planes + crtc + encoder + connector)
|
||||
// active output pipelines (planes + crtc + encoder + connector)
|
||||
QVector<DrmOutput*> m_outputs;
|
||||
// active and enabled pipelines (above + wl_output)
|
||||
QVector<DrmOutput*> m_enabledOutputs;
|
||||
|
||||
bool m_deleteBufferAfterPageFlip;
|
||||
bool m_atomicModeSetting = false;
|
||||
bool m_cursorEnabled = false;
|
||||
|
|
|
@ -183,6 +183,26 @@ qreal DrmOutput::scale() const
|
|||
return m_scale;
|
||||
}
|
||||
|
||||
void DrmOutput::setEnabled(bool enabled)
|
||||
{
|
||||
if (enabled == isEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (enabled) {
|
||||
setDpms(DpmsMode::On);
|
||||
initOutput();
|
||||
} else {
|
||||
setDpms(DpmsMode::Off);
|
||||
delete m_waylandOutput.data();
|
||||
}
|
||||
m_waylandOutputDevice->setEnabled(enabled ?
|
||||
KWayland::Server::OutputDeviceInterface::Enablement::Enabled : KWayland::Server::OutputDeviceInterface::Enablement::Disabled);
|
||||
}
|
||||
|
||||
bool DrmOutput::isEnabled() const
|
||||
{
|
||||
return !m_waylandOutput.isNull();
|
||||
}
|
||||
|
||||
static KWayland::Server::OutputInterface::DpmsMode toWaylandDpmsMode(DrmOutput::DpmsMode mode)
|
||||
{
|
||||
|
@ -272,8 +292,6 @@ bool DrmOutput::init(drmModeConnector *connector)
|
|||
|
||||
m_internal = connector->connector_type == DRM_MODE_CONNECTOR_LVDS || connector->connector_type == DRM_MODE_CONNECTOR_eDP;
|
||||
|
||||
setDpms(DpmsMode::On);
|
||||
|
||||
if (m_internal) {
|
||||
connect(kwinApp(), &Application::screensCreated, this,
|
||||
[this] {
|
||||
|
@ -297,8 +315,8 @@ bool DrmOutput::init(drmModeConnector *connector)
|
|||
m_physicalSize = physicalSize;
|
||||
|
||||
initOutputDevice(connector);
|
||||
initOutput();
|
||||
|
||||
setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -784,18 +802,13 @@ void DrmOutput::setChanges(KWayland::Server::OutputChangeSet *changes)
|
|||
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());
|
||||
}
|
||||
//enabledChanged is handled by drmbackend
|
||||
if (m_changeset->modeChanged()) {
|
||||
qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode();
|
||||
m_waylandOutputDevice->setCurrentMode(m_changeset->mode());
|
||||
|
|
|
@ -75,6 +75,15 @@ public:
|
|||
bool present(DrmBuffer *buffer);
|
||||
void pageFlipped();
|
||||
|
||||
/**
|
||||
* Enable or disable the output.
|
||||
* This differs from setDpms as it also
|
||||
* removes the wl_output
|
||||
* The default is on
|
||||
*/
|
||||
void setEnabled(bool enabled);
|
||||
bool isEnabled() const;
|
||||
|
||||
/**
|
||||
* This sets the changes and tests them against the DRM output
|
||||
*/
|
||||
|
|
|
@ -43,7 +43,7 @@ void DrmScreens::init()
|
|||
|
||||
QRect DrmScreens::geometry(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return QRect();
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ QRect DrmScreens::geometry(int screen) const
|
|||
|
||||
qreal DrmScreens::scale(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ qreal DrmScreens::scale(int screen) const
|
|||
|
||||
QSize DrmScreens::size(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return QSize();
|
||||
}
|
||||
|
@ -70,14 +70,14 @@ QSize DrmScreens::size(int screen) const
|
|||
|
||||
void DrmScreens::updateCount()
|
||||
{
|
||||
setCount(m_backend->outputs().size());
|
||||
setCount(m_backend->enabledOutputs().size());
|
||||
}
|
||||
|
||||
int DrmScreens::number(const QPoint &pos) const
|
||||
{
|
||||
int bestScreen = 0;
|
||||
int minDistance = INT_MAX;
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
for (int i = 0; i < outputs.size(); ++i) {
|
||||
const QRect &geo = outputs.at(i)->geometry();
|
||||
if (geo.contains(pos)) {
|
||||
|
@ -97,7 +97,7 @@ int DrmScreens::number(const QPoint &pos) const
|
|||
|
||||
QString DrmScreens::name(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return Screens::name(screen);
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ QString DrmScreens::name(int screen) const
|
|||
|
||||
float DrmScreens::refreshRate(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return Screens::refreshRate(screen);
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ float DrmScreens::refreshRate(int screen) const
|
|||
|
||||
QSizeF DrmScreens::physicalSize(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return Screens::physicalSize(screen);
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ QSizeF DrmScreens::physicalSize(int screen) const
|
|||
|
||||
bool DrmScreens::isInternal(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ bool DrmScreens::isInternal(int screen) const
|
|||
|
||||
bool DrmScreens::supportsTransformations(int screen) const
|
||||
{
|
||||
const auto outputs = m_backend->outputs();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
if (screen >= outputs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue