Add OutputManager for taking care of output settings in KWin
As a first step to move away from having an external service remember output settings for KWin, this commit introduces an output manager that can load configuration files and generate new output configurations.
This commit is contained in:
parent
6b8e08dfa9
commit
c51824b535
15 changed files with 214 additions and 33 deletions
|
@ -108,6 +108,7 @@ target_sources(kwin PRIVATE
|
||||||
options.cpp
|
options.cpp
|
||||||
osd.cpp
|
osd.cpp
|
||||||
outline.cpp
|
outline.cpp
|
||||||
|
outputconfigurationstore.cpp
|
||||||
placeholderinputeventfilter.cpp
|
placeholderinputeventfilter.cpp
|
||||||
placeholderoutput.cpp
|
placeholderoutput.cpp
|
||||||
placement.cpp
|
placement.cpp
|
||||||
|
|
|
@ -473,11 +473,13 @@ bool DrmBackend::applyOutputChanges(const OutputConfiguration &config)
|
||||||
if (output->isNonDesktop()) {
|
if (output->isNonDesktop()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
output->queueChanges(config);
|
if (const auto changeset = config.constChangeSet(output)) {
|
||||||
if (config.constChangeSet(output)->enabled) {
|
output->queueChanges(config);
|
||||||
toBeEnabled << output;
|
if (changeset->enabled) {
|
||||||
} else {
|
toBeEnabled << output;
|
||||||
toBeDisabled << output;
|
} else {
|
||||||
|
toBeDisabled << output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gpu->testPendingConfiguration() != DrmPipeline::Error::None) {
|
if (gpu->testPendingConfiguration() != DrmPipeline::Error::None) {
|
||||||
|
|
|
@ -77,7 +77,7 @@ DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
|
||||||
.serialNumber = edid->serialNumber(),
|
.serialNumber = edid->serialNumber(),
|
||||||
.eisaId = edid->eisaId(),
|
.eisaId = edid->eisaId(),
|
||||||
.physicalSize = conn->physicalSize(),
|
.physicalSize = conn->physicalSize(),
|
||||||
.edid = edid->raw(),
|
.edid = *edid,
|
||||||
.subPixel = conn->subpixel(),
|
.subPixel = conn->subpixel(),
|
||||||
.capabilities = capabilities,
|
.capabilities = capabilities,
|
||||||
.panelOrientation = DrmConnector::toKWinTransform(conn->panelOrientation()),
|
.panelOrientation = DrmConnector::toKWinTransform(conn->panelOrientation()),
|
||||||
|
|
|
@ -377,7 +377,7 @@ void X11StandaloneBackend::doUpdateOutputs()
|
||||||
information.manufacturer = edid.manufacturerString();
|
information.manufacturer = edid.manufacturerString();
|
||||||
information.model = edid.monitorName();
|
information.model = edid.monitorName();
|
||||||
information.serialNumber = edid.serialNumber();
|
information.serialNumber = edid.serialNumber();
|
||||||
information.edid = data;
|
information.edid = edid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ QSize Output::pixelSize() const
|
||||||
return orientateSize(modeSize());
|
return orientateSize(modeSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Output::edid() const
|
const Edid &Output::edid() const
|
||||||
{
|
{
|
||||||
return m_information.edid;
|
return m_information.edid;
|
||||||
}
|
}
|
||||||
|
@ -222,6 +222,9 @@ Output::SubPixel Output::subPixel() const
|
||||||
void Output::applyChanges(const OutputConfiguration &config)
|
void Output::applyChanges(const OutputConfiguration &config)
|
||||||
{
|
{
|
||||||
auto props = config.constChangeSet(this);
|
auto props = config.constChangeSet(this);
|
||||||
|
if (!props) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Q_EMIT aboutToChange();
|
Q_EMIT aboutToChange();
|
||||||
|
|
||||||
State next = m_state;
|
State next = m_state;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <kwin_export.h>
|
#include <kwin_export.h>
|
||||||
|
|
||||||
#include "renderloop.h"
|
#include "renderloop.h"
|
||||||
|
#include "utils/edid.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QMatrix3x3>
|
#include <QMatrix3x3>
|
||||||
|
@ -235,7 +236,7 @@ public:
|
||||||
SubPixel subPixel() const;
|
SubPixel subPixel() const;
|
||||||
QString description() const;
|
QString description() const;
|
||||||
Capabilities capabilities() const;
|
Capabilities capabilities() const;
|
||||||
QByteArray edid() const;
|
const Edid &edid() const;
|
||||||
QList<std::shared_ptr<OutputMode>> modes() const;
|
QList<std::shared_ptr<OutputMode>> modes() const;
|
||||||
std::shared_ptr<OutputMode> currentMode() const;
|
std::shared_ptr<OutputMode> currentMode() const;
|
||||||
DpmsMode dpmsMode() const;
|
DpmsMode dpmsMode() const;
|
||||||
|
@ -328,7 +329,7 @@ protected:
|
||||||
QString serialNumber;
|
QString serialNumber;
|
||||||
QString eisaId;
|
QString eisaId;
|
||||||
QSize physicalSize;
|
QSize physicalSize;
|
||||||
QByteArray edid;
|
Edid edid;
|
||||||
SubPixel subPixel = SubPixel::Unknown;
|
SubPixel subPixel = SubPixel::Unknown;
|
||||||
Capabilities capabilities;
|
Capabilities capabilities;
|
||||||
Transform panelOrientation = Transform::Normal;
|
Transform panelOrientation = Transform::Normal;
|
||||||
|
|
|
@ -65,10 +65,12 @@ bool OutputBackend::applyOutputChanges(const OutputConfiguration &config)
|
||||||
QVector<Output *> toBeEnabledOutputs;
|
QVector<Output *> toBeEnabledOutputs;
|
||||||
QVector<Output *> toBeDisabledOutputs;
|
QVector<Output *> toBeDisabledOutputs;
|
||||||
for (const auto &output : availableOutputs) {
|
for (const auto &output : availableOutputs) {
|
||||||
if (config.constChangeSet(output)->enabled) {
|
if (const auto changeset = config.constChangeSet(output)) {
|
||||||
toBeEnabledOutputs << output;
|
if (changeset->enabled) {
|
||||||
} else {
|
toBeEnabledOutputs << output;
|
||||||
toBeDisabledOutputs << output;
|
} else {
|
||||||
|
toBeDisabledOutputs << output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &output : toBeEnabledOutputs) {
|
for (const auto &output : toBeEnabledOutputs) {
|
||||||
|
|
|
@ -26,10 +26,8 @@ namespace KScreenIntegration
|
||||||
/// See KScreen::Output::hashMd5
|
/// See KScreen::Output::hashMd5
|
||||||
static QString outputHash(Output *output)
|
static QString outputHash(Output *output)
|
||||||
{
|
{
|
||||||
if (!output->edid().isEmpty()) {
|
if (output->edid().isValid()) {
|
||||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
return output->edid().hash();
|
||||||
hash.addData(output->edid());
|
|
||||||
return QString::fromLatin1(hash.result().toHex());
|
|
||||||
} else {
|
} else {
|
||||||
return output->name();
|
return output->name();
|
||||||
}
|
}
|
||||||
|
|
132
src/outputconfigurationstore.cpp
Normal file
132
src/outputconfigurationstore.cpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
#include "outputconfigurationstore.h"
|
||||||
|
#include "core/inputdevice.h"
|
||||||
|
#include "core/output.h"
|
||||||
|
#include "core/outputconfiguration.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "kscreenintegration.h"
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
std::pair<OutputConfiguration, QVector<Output *>> OutputConfigurationStore::queryConfig(const QVector<Output *> &outputs)
|
||||||
|
{
|
||||||
|
const auto kscreenConfig = KScreenIntegration::readOutputConfig(outputs, KScreenIntegration::connectedOutputsHash(outputs));
|
||||||
|
if (kscreenConfig) {
|
||||||
|
return kscreenConfig.value();
|
||||||
|
} else {
|
||||||
|
// no config file atm -> generate a new one
|
||||||
|
return generateConfig(outputs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<OutputConfiguration, QVector<Output *>> OutputConfigurationStore::generateConfig(const QVector<Output *> &outputs) const
|
||||||
|
{
|
||||||
|
OutputConfiguration ret;
|
||||||
|
|
||||||
|
QPoint pos(0, 0);
|
||||||
|
for (const auto output : outputs) {
|
||||||
|
const auto mode = chooseMode(output);
|
||||||
|
const double scale = chooseScale(output, mode.get());
|
||||||
|
*ret.changeSet(output) = {
|
||||||
|
.mode = mode,
|
||||||
|
.enabled = true,
|
||||||
|
.pos = pos,
|
||||||
|
.scale = scale,
|
||||||
|
.transform = output->panelOrientation(),
|
||||||
|
.overscan = 0,
|
||||||
|
.rgbRange = Output::RgbRange::Automatic,
|
||||||
|
.vrrPolicy = RenderLoop::VrrPolicy::Automatic,
|
||||||
|
};
|
||||||
|
pos.setX(pos.x() + mode->size().width() / scale);
|
||||||
|
}
|
||||||
|
return std::make_pair(ret, outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OutputMode> OutputConfigurationStore::chooseMode(Output *output) const
|
||||||
|
{
|
||||||
|
const auto modes = output->modes();
|
||||||
|
|
||||||
|
// some displays advertise bigger modes than their native resolution
|
||||||
|
// to avoid that, take the preferred mode into account, which is usually the native one
|
||||||
|
const auto preferred = std::find_if(modes.begin(), modes.end(), [](const auto &mode) {
|
||||||
|
return mode->flags() & OutputMode::Flag::Preferred;
|
||||||
|
});
|
||||||
|
if (preferred != modes.end()) {
|
||||||
|
// some high refresh rate displays advertise a 60Hz mode as preferred for compatibility reasons
|
||||||
|
// ignore that and choose the highest possible refresh rate by default instead
|
||||||
|
std::shared_ptr<OutputMode> highestRefresh = *preferred;
|
||||||
|
for (const auto &mode : modes) {
|
||||||
|
if (mode->size() == highestRefresh->size() && mode->refreshRate() > highestRefresh->refreshRate()) {
|
||||||
|
highestRefresh = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the preferred mode size has a refresh rate that's too low for PCs,
|
||||||
|
// allow falling back to a mode with lower resolution and a more usable refresh rate
|
||||||
|
if (highestRefresh->refreshRate() >= 50000) {
|
||||||
|
return highestRefresh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OutputMode> ret;
|
||||||
|
for (auto mode : modes) {
|
||||||
|
if (!ret) {
|
||||||
|
ret = mode;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const bool retUsableRefreshRate = ret->refreshRate() >= 50000;
|
||||||
|
const bool usableRefreshRate = mode->refreshRate() >= 50000;
|
||||||
|
if (retUsableRefreshRate && !usableRefreshRate) {
|
||||||
|
ret = mode;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((usableRefreshRate && !retUsableRefreshRate)
|
||||||
|
|| mode->size().width() > ret->size().width()
|
||||||
|
|| mode->size().height() > ret->size().height()
|
||||||
|
|| (mode->size() == ret->size() && mode->refreshRate() > ret->refreshRate())) {
|
||||||
|
ret = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
double OutputConfigurationStore::chooseScale(Output *output, OutputMode *mode) const
|
||||||
|
{
|
||||||
|
if (output->physicalSize().height() <= 0) {
|
||||||
|
// invalid size, can't do anything with this
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
const double outputDpi = mode->size().height() / (output->physicalSize().height() / 25.4);
|
||||||
|
const double desiredScale = outputDpi / targetDpi(output);
|
||||||
|
// round to 25% steps
|
||||||
|
return std::round(100.0 * desiredScale / 25.0) * 100.0 / 25.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double OutputConfigurationStore::targetDpi(Output *output) const
|
||||||
|
{
|
||||||
|
const auto devices = input()->devices();
|
||||||
|
const bool hasLaptopLid = std::any_of(devices.begin(), devices.end(), [](const auto &device) {
|
||||||
|
return device->isLidSwitch();
|
||||||
|
});
|
||||||
|
if (output->isInternal()) {
|
||||||
|
if (hasLaptopLid) {
|
||||||
|
// laptop screens: usually closer to the face than desktop monitors
|
||||||
|
return 125;
|
||||||
|
} else {
|
||||||
|
// phone screens: even closer than laptops
|
||||||
|
return 136;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "normal" 1x scale desktop monitor dpi
|
||||||
|
return 96;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
src/outputconfigurationstore.h
Normal file
33
src/outputconfigurationstore.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QVector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
class OutputConfiguration;
|
||||||
|
class Output;
|
||||||
|
class OutputMode;
|
||||||
|
|
||||||
|
class OutputConfigurationStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::pair<OutputConfiguration, QVector<Output *>> queryConfig(const QVector<Output *> &outputs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::pair<OutputConfiguration, QVector<Output *>> generateConfig(const QVector<Output *> &outputs) const;
|
||||||
|
std::shared_ptr<OutputMode> chooseMode(Output *output) const;
|
||||||
|
double chooseScale(Output *output, OutputMode *mode) const;
|
||||||
|
double targetDpi(Output *output) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
@ -175,6 +176,9 @@ Edid::Edid(const void *data, uint32_t size)
|
||||||
m_monitorName = parseMonitorName(bytes);
|
m_monitorName = parseMonitorName(bytes);
|
||||||
m_serialNumber = parseSerialNumber(bytes);
|
m_serialNumber = parseSerialNumber(bytes);
|
||||||
m_vendor = parseVendor(bytes);
|
m_vendor = parseVendor(bytes);
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||||
|
hash.addData(m_raw);
|
||||||
|
m_hash = QString::fromLatin1(hash.result().toHex());
|
||||||
|
|
||||||
m_isValid = true;
|
m_isValid = true;
|
||||||
}
|
}
|
||||||
|
@ -241,4 +245,9 @@ QString Edid::nameString() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Edid::hash() const
|
||||||
|
{
|
||||||
|
return m_hash;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace KWin
|
} // namespace KWin
|
||||||
|
|
|
@ -74,12 +74,15 @@ public:
|
||||||
*/
|
*/
|
||||||
QString nameString() const;
|
QString nameString() const;
|
||||||
|
|
||||||
|
QString hash() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSize m_physicalSize;
|
QSize m_physicalSize;
|
||||||
QByteArray m_vendor;
|
QByteArray m_vendor;
|
||||||
QByteArray m_eisaId;
|
QByteArray m_eisaId;
|
||||||
QByteArray m_monitorName;
|
QByteArray m_monitorName;
|
||||||
QByteArray m_serialNumber;
|
QByteArray m_serialNumber;
|
||||||
|
QString m_hash;
|
||||||
|
|
||||||
QByteArray m_raw;
|
QByteArray m_raw;
|
||||||
bool m_isValid = false;
|
bool m_isValid = false;
|
||||||
|
|
|
@ -484,7 +484,7 @@ void OutputDeviceV2Interface::updateCurrentMode()
|
||||||
|
|
||||||
void OutputDeviceV2Interface::updateEdid()
|
void OutputDeviceV2Interface::updateEdid()
|
||||||
{
|
{
|
||||||
d->m_edid = d->m_handle->edid();
|
d->m_edid = d->m_handle->edid().raw();
|
||||||
const auto clientResources = d->resourceMap();
|
const auto clientResources = d->resourceMap();
|
||||||
for (const auto &resource : clientResources) {
|
for (const auto &resource : clientResources) {
|
||||||
d->sendEdid(resource);
|
d->sendEdid(resource);
|
||||||
|
|
|
@ -46,8 +46,8 @@
|
||||||
#include "tabbox/tabbox.h"
|
#include "tabbox/tabbox.h"
|
||||||
#endif
|
#endif
|
||||||
#include "decorations/decorationbridge.h"
|
#include "decorations/decorationbridge.h"
|
||||||
#include "kscreenintegration.h"
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "outputconfigurationstore.h"
|
||||||
#include "placeholderinputeventfilter.h"
|
#include "placeholderinputeventfilter.h"
|
||||||
#include "placeholderoutput.h"
|
#include "placeholderoutput.h"
|
||||||
#include "placementtracker.h"
|
#include "placementtracker.h"
|
||||||
|
@ -130,6 +130,7 @@ Workspace::Workspace()
|
||||||
, m_focusChain(std::make_unique<FocusChain>())
|
, m_focusChain(std::make_unique<FocusChain>())
|
||||||
, m_applicationMenu(std::make_unique<ApplicationMenu>())
|
, m_applicationMenu(std::make_unique<ApplicationMenu>())
|
||||||
, m_placementTracker(std::make_unique<PlacementTracker>(this))
|
, m_placementTracker(std::make_unique<PlacementTracker>(this))
|
||||||
|
, m_outputConfigStore(std::make_unique<OutputConfigurationStore>())
|
||||||
{
|
{
|
||||||
// If KWin was already running it saved its configuration after loosing the selection -> Reread
|
// If KWin was already running it saved its configuration after loosing the selection -> Reread
|
||||||
QFuture<void> reparseConfigFuture = QtConcurrent::run(&Options::reparseConfiguration, options);
|
QFuture<void> reparseConfigFuture = QtConcurrent::run(&Options::reparseConfiguration, options);
|
||||||
|
@ -277,8 +278,8 @@ QString Workspace::getPlacementTrackerHash()
|
||||||
QStringList hashes;
|
QStringList hashes;
|
||||||
for (const auto &output : std::as_const(m_outputs)) {
|
for (const auto &output : std::as_const(m_outputs)) {
|
||||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||||
if (!output->edid().isEmpty()) {
|
if (output->edid().isValid()) {
|
||||||
hash.addData(output->edid());
|
hash.addData(output->edid().raw());
|
||||||
} else {
|
} else {
|
||||||
hash.addData(output->name().toLatin1());
|
hash.addData(output->name().toLatin1());
|
||||||
}
|
}
|
||||||
|
@ -537,18 +538,13 @@ void Workspace::updateOutputConfiguration()
|
||||||
setOutputOrder(newOrder);
|
setOutputOrder(newOrder);
|
||||||
};
|
};
|
||||||
|
|
||||||
m_outputsHash = KScreenIntegration::connectedOutputsHash(outputs);
|
const auto &[cfg, order] = m_outputConfigStore->queryConfig(outputs);
|
||||||
if (const auto config = KScreenIntegration::readOutputConfig(outputs, m_outputsHash)) {
|
if (!kwinApp()->outputBackend()->applyOutputChanges(cfg)) {
|
||||||
const auto &[cfg, order] = config.value();
|
qCWarning(KWIN_CORE) << "Applying output config failed!";
|
||||||
if (!kwinApp()->outputBackend()->applyOutputChanges(cfg)) {
|
|
||||||
qCWarning(KWIN_CORE) << "Applying KScreen config failed!";
|
|
||||||
setFallbackOutputOrder();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setOutputOrder(order);
|
|
||||||
} else {
|
|
||||||
setFallbackOutputOrder();
|
setFallbackOutputOrder();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
setOutputOrder(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::setupWindowConnections(Window *window)
|
void Workspace::setupWindowConnections(Window *window)
|
||||||
|
|
|
@ -78,6 +78,7 @@ class PlaceholderOutput;
|
||||||
class Placement;
|
class Placement;
|
||||||
class OutputConfiguration;
|
class OutputConfiguration;
|
||||||
class TileManager;
|
class TileManager;
|
||||||
|
class OutputConfigurationStore;
|
||||||
|
|
||||||
class KWIN_EXPORT Workspace : public QObject
|
class KWIN_EXPORT Workspace : public QObject
|
||||||
{
|
{
|
||||||
|
@ -632,7 +633,6 @@ private:
|
||||||
QList<Output *> m_outputs;
|
QList<Output *> m_outputs;
|
||||||
Output *m_activeOutput = nullptr;
|
Output *m_activeOutput = nullptr;
|
||||||
Output *m_activeCursorOutput = nullptr;
|
Output *m_activeCursorOutput = nullptr;
|
||||||
QString m_outputsHash;
|
|
||||||
QVector<Output *> m_outputOrder;
|
QVector<Output *> m_outputOrder;
|
||||||
|
|
||||||
Window *m_activeWindow;
|
Window *m_activeWindow;
|
||||||
|
@ -723,6 +723,7 @@ private:
|
||||||
PlaceholderOutput *m_placeholderOutput = nullptr;
|
PlaceholderOutput *m_placeholderOutput = nullptr;
|
||||||
std::unique_ptr<PlaceholderInputEventFilter> m_placeholderFilter;
|
std::unique_ptr<PlaceholderInputEventFilter> m_placeholderFilter;
|
||||||
std::map<Output *, std::unique_ptr<TileManager>> m_tileManagers;
|
std::map<Output *, std::unique_ptr<TileManager>> m_tileManagers;
|
||||||
|
std::unique_ptr<OutputConfigurationStore> m_outputConfigStore;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend bool performTransiencyCheck();
|
friend bool performTransiencyCheck();
|
||||||
|
|
Loading…
Reference in a new issue