diff --git a/console/console.cpp b/console/console.cpp index 8225c0e..add36cb 100644 --- a/console/console.cpp +++ b/console/console.cpp @@ -1,224 +1,224 @@ /************************************************************************************* * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "console.h" -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include #include #include #include #include #include #include static QTextStream cout(stdout); namespace KScreen { namespace ConfigSerializer { // Exported private symbol in configserializer_p.h in KScreen extern QJsonObject serializeConfig(const KScreen::ConfigPtr &config); } } using namespace KScreen; Console::Console(const ConfigPtr &config) : QObject() , m_config(config) { } Console::~Console() { } #include void Console::printConfig() { if (!m_config) { qDebug() << "Config is invalid, probably backend couldn't load"; return; } if (!m_config->screen()) { qDebug() << "No screen in the configuration, broken backend"; return; } connect(m_config.data(), &Config::primaryOutputChanged, [&](const OutputPtr &output) { if (output) { qDebug() << "New primary output: " << output->id() << output->name(); } else { qDebug() << "No primary output."; } }); qDebug() << "Screen:"; qDebug() << "\tmaxSize:" << m_config->screen()->maxSize(); qDebug() << "\tminSize:" << m_config->screen()->minSize(); qDebug() << "\tcurrentSize:" << m_config->screen()->currentSize(); OutputList outputs = m_config->outputs(); Q_FOREACH(const OutputPtr &output, outputs) { qDebug() << "\n-----------------------------------------------------\n"; qDebug() << "Id: " << output->id(); qDebug() << "Name: " << output->name(); qDebug() << "Type: " << typetoString(output->type()); qDebug() << "Connected: " << output->isConnected(); if (!output->isConnected()) { continue; } qDebug() << "Enabled: " << output->isEnabled(); qDebug() << "Primary: " << output->isPrimary(); qDebug() << "Rotation: " << output->rotation(); qDebug() << "Pos: " << output->pos(); qDebug() << "MMSize: " << output->sizeMm(); if (output->currentMode()) { qDebug() << "Size: " << output->size(); } qDebug() << "Scale: " << output->scale(); if (output->clones().isEmpty()) { qDebug() << "Clones: " << "None"; } else { qDebug() << "Clones: " << output->clones().count(); } qDebug() << "Mode: " << output->currentModeId(); qDebug() << "Preferred Mode: " << output->preferredModeId(); qDebug() << "Preferred modes: " << output->preferredModes(); qDebug() << "Modes: "; ModeList modes = output->modes(); Q_FOREACH(const ModePtr &mode, modes) { qDebug() << "\t" << mode->id() << " " << mode->name() << " " << mode->size() << " " << mode->refreshRate(); } Edid* edid = output->edid(); qDebug() << "EDID Info: "; if (edid && edid->isValid()) { qDebug() << "\tDevice ID: " << edid->deviceId(); qDebug() << "\tName: " << edid->name(); qDebug() << "\tVendor: " << edid->vendor(); qDebug() << "\tSerial: " << edid->serial(); qDebug() << "\tEISA ID: " << edid->eisaId(); qDebug() << "\tHash: " << edid->hash(); qDebug() << "\tWidth: " << edid->width(); qDebug() << "\tHeight: " << edid->height(); qDebug() << "\tGamma: " << edid->gamma(); qDebug() << "\tRed: " << edid->red(); qDebug() << "\tGreen: " << edid->green(); qDebug() << "\tBlue: " << edid->blue(); qDebug() << "\tWhite: " << edid->white(); } else { qDebug() << "\tUnavailable"; } } } QString Console::typetoString(const Output::Type& type) const { switch (type) { case Output::Unknown: return QStringLiteral("Unknown"); case Output::Panel: return QStringLiteral("Panel (Laptop)"); case Output::VGA: return QStringLiteral("VGA"); case Output::DVI: return QStringLiteral("DVI"); case Output::DVII: return QStringLiteral("DVI-I"); case Output::DVIA: return QStringLiteral("DVI-A"); case Output::DVID: return QStringLiteral("DVI-D"); case Output::HDMI: return QStringLiteral("HDMI"); case Output::TV: return QStringLiteral("TV"); case Output::TVComposite: return QStringLiteral("TV-Composite"); case Output::TVSVideo: return QStringLiteral("TV-SVideo"); case Output::TVComponent: return QStringLiteral("TV-Component"); case Output::TVSCART: return QStringLiteral("TV-SCART"); case Output::TVC4: return QStringLiteral("TV-C4"); case Output::DisplayPort: return QStringLiteral("DisplayPort"); }; return QStringLiteral("Invalid Type") + QString::number(type); } void Console::printJSONConfig() { QJsonDocument doc(KScreen::ConfigSerializer::serializeConfig(m_config)); cout << doc.toJson(QJsonDocument::Indented); } void Console::printSerializations() { QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kscreen/"; qDebug() << "Configs in: " << path; QDir dir(path); QStringList files = dir.entryList(QDir::Files); qDebug() << "Number of files: " << files.count() << endl; QJsonDocument parser; Q_FOREACH(const QString fileName, files) { QJsonParseError error; qDebug() << fileName; QFile file(path + "/" + fileName); file.open(QFile::ReadOnly); QVariant data = parser.fromJson(file.readAll(), &error); if (error.error != QJsonParseError::NoError) { qDebug() << " " << "can't parse file"; qDebug() << " " << error.errorString(); continue; } qDebug() << parser.toJson(QJsonDocument::Indented) << endl; } } void Console::monitor() { ConfigMonitor::instance()->addConfig(m_config); } void Console::monitorAndPrint() { monitor(); connect(ConfigMonitor::instance(), &ConfigMonitor::configurationChanged, this, &Console::printConfig); } diff --git a/console/main.cpp b/console/main.cpp index fe5d734..a61218b 100644 --- a/console/main.cpp +++ b/console/main.cpp @@ -1,127 +1,127 @@ /************************************************************************************* * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include #include #include #include -#include +#include #include #include #include #include #include "console.h" using namespace std; void configReceived(KScreen::ConfigOperation *op) { const KScreen::ConfigPtr config = qobject_cast(op)->config(); const QString command = op->property("command").toString(); const qint64 msecs = QDateTime::currentMSecsSinceEpoch() - op->property("start").toLongLong(); qDebug() << "Received config. Took" << msecs << "milliseconds"; Console *console = new Console(config); if (command.isEmpty()) { console->printConfig(); console->monitorAndPrint(); } else if (command == QLatin1String("monitor")) { QTextStream(stdout) << "Remember to enable KSRandR or KSRandR11 in kdebugdialog" << endl; //Print config so that we have some pivot data console->printConfig(); console->monitor(); //Do nothing, enable backend output to see debug } else if (command == QLatin1String("outputs")) { console->printConfig(); qApp->quit(); } else if (command == QLatin1String("config")) { console->printSerializations(); qApp->quit(); } else if (command == QLatin1String("bug")) { QTextStream(stdout) << QStringLiteral("\n========================xrandr --verbose==========================\n"); QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start(QStringLiteral("xrandr"), QStringList(QStringLiteral("--verbose"))); proc.waitForFinished(); QTextStream(stdout) << proc.readAll().data(); QTextStream(stdout) << QStringLiteral("\n========================Outputs===================================\n"); console->printConfig(); QTextStream(stdout) << QStringLiteral("\n========================Configurations============================\n"); console->printSerializations(); qApp->quit(); } else if (command == QLatin1String("json")) { console->printJSONConfig(); qApp->quit(); } else { qApp->quit(); } } int main (int argc, char *argv[]) { dup2(1, 2); QGuiApplication app(argc, argv); KAboutData aboutData(QStringLiteral("kscreen-console"), i18n("KScreen Console"), QStringLiteral("1.0"), i18n("KScreen Console"), KAboutLicense::GPL, i18n("(c) 2012 KScreen Team")); KAboutData::setApplicationData(aboutData); aboutData.addAuthor(i18n("Alejandro Fiestas Olivares"), i18n("Maintainer"), QStringLiteral("afiestas@kde.org"), QStringLiteral("http://www.afiestas.org/")); QCommandLineParser parser; parser.setApplicationDescription( i18n("KScreen Console is a CLI tool to query KScreen status\n\n" "Commands:\n" " bug Show information needed for a bug report\n" " config Show KScreen config files\n" " outputs Show output information\n" " monitor Monitor for changes\n" " json Show current KScreen config")); parser.addHelpOption(); parser.addPositionalArgument(QStringLiteral("command"), i18n("Command to execute"), QStringLiteral("bug|config|outputs|monitor|json")); parser.addPositionalArgument(QStringLiteral("[args...]"), i18n("Arguments for the specified command")); parser.process(app); QString command; if (!parser.positionalArguments().isEmpty()) { command = parser.positionalArguments().first(); } qDebug() << "START: Requesting Config"; KScreen::GetConfigOperation *op = new KScreen::GetConfigOperation(); op->setProperty("command", command); op->setProperty("start", QDateTime::currentMSecsSinceEpoch()); QObject::connect(op, &KScreen::GetConfigOperation::finished, [&](KScreen::ConfigOperation *op) { configReceived(op); }); app.exec(); } diff --git a/kcm/src/outputconfig.cpp b/kcm/src/outputconfig.cpp index 7180a0d..c02a11c 100644 --- a/kcm/src/outputconfig.cpp +++ b/kcm/src/outputconfig.cpp @@ -1,263 +1,263 @@ /* * Copyright 2013 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "outputconfig.h" #include "resolutionslider.h" #include "collapsablebutton.h" #include "utils.h" #include "kcm_screen_debug.h" -#include +#include #include #include #include #include #include #include #include #include #include #include #include OutputConfig::OutputConfig(QWidget *parent) : QWidget(parent) , mOutput(nullptr) { } OutputConfig::OutputConfig(const KScreen::OutputPtr &output, QWidget *parent) : QWidget(parent) { setOutput(output); } OutputConfig::~OutputConfig() { } void OutputConfig::setTitle(const QString& title) { mTitle->setText(title); } void OutputConfig::initUi() { connect(mOutput.data(), &KScreen::Output::isConnectedChanged, this, [=]() { if (!mOutput->isConnected()) { setVisible(false); } }); connect(mOutput.data(), &KScreen::Output::isEnabledChanged, this, [=]() { mEnabled->setChecked(mOutput->isEnabled()); }); connect(mOutput.data(), &KScreen::Output::rotationChanged, this, [=]() { const int index = mRotation->findData(mOutput->rotation()); mRotation->setCurrentIndex(index); }); connect(mOutput.data(), &KScreen::Output::scaleChanged, this, [=]() { const int index = mScale->findData(mOutput->scale()); mScale->setCurrentIndex(index); }); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QVBoxLayout *vbox = new QVBoxLayout(this); mTitle = new QLabel(this); mTitle->setAlignment(Qt::AlignHCenter); vbox->addWidget(mTitle); setTitle(Utils::outputName(mOutput)); QFormLayout *formLayout = new QFormLayout(); vbox->addLayout(formLayout); mEnabled = new QCheckBox(i18n("Enabled"), this); mEnabled->setChecked(mOutput->isEnabled()); connect(mEnabled, &QCheckBox::clicked, this, [=](bool checked) { mOutput->setEnabled(checked); qCDebug(KSCREEN_KCM) << mOutput.data() << mOutput->name() << mOutput->isEnabled(); Q_EMIT changed(); }); formLayout->addRow(i18n("Display:"), mEnabled); mResolution = new ResolutionSlider(mOutput, this); connect(mResolution, &ResolutionSlider::resolutionChanged, this, &OutputConfig::slotResolutionChanged); formLayout->addRow(i18n("Resolution:"), mResolution); mRotation = new QComboBox(this); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-up")), i18n("Normal"), KScreen::Output::None); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-right")), i18n("90° Clockwise"), KScreen::Output::Right); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-down")), i18n("Upside Down"), KScreen::Output::Inverted); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-left")), i18n("90° Counterclockwise"), KScreen::Output::Left); connect(mRotation, static_cast(&QComboBox::activated), this, &OutputConfig::slotRotationChanged); mRotation->setCurrentIndex(mRotation->findData(mOutput->rotation())); formLayout->addRow(i18n("Orientation:"), mRotation); if (mShowScaleOption) { mScale = new QComboBox(this); mScale->addItem(i18nc("Scale multiplier, show everything at 1 times normal scale", "1x"), 1); mScale->addItem(i18nc("Scale multiplier, show everything at 2 times normal scale", "2x"), 2); connect(mScale, static_cast(&QComboBox::activated), this, &OutputConfig::slotScaleChanged); mScale->setCurrentIndex(mScale->findData(mOutput->scale())); formLayout->addRow(i18n("Scale:"), mScale); formLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum)); } CollapsableButton *advancedButton = new CollapsableButton(i18n("Advanced Settings"), this); advancedButton->setCollapsed(true); vbox->addWidget(advancedButton); QWidget *advancedWidget = new QWidget(this); int leftMargin, topMargin, rightMargin, bottomMargin; advancedWidget->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); advancedWidget->setContentsMargins(25, topMargin, rightMargin, bottomMargin); vbox->addWidget(advancedWidget); advancedButton->setWidget(advancedWidget); formLayout = new QFormLayout(advancedWidget); advancedWidget->setLayout(formLayout); mRefreshRate = new QComboBox(advancedWidget); mRefreshRate->addItem(i18n("Auto"), -1); formLayout->addRow(i18n("Refresh rate:"), mRefreshRate); slotResolutionChanged(mResolution->currentResolution()); connect(mRefreshRate, static_cast(&QComboBox::activated), this, &OutputConfig::slotRefreshRateChanged); vbox->addStretch(2); } void OutputConfig::setOutput(const KScreen::OutputPtr &output) { mOutput = output; initUi(); } KScreen::OutputPtr OutputConfig::output() const { return mOutput; } void OutputConfig::slotResolutionChanged(const QSize &size) { // Ignore disconnected outputs if (!size.isValid()) { return; } KScreen::ModePtr selectedMode; QList modes; Q_FOREACH (const KScreen::ModePtr &mode, mOutput->modes()) { if (mode->size() == size) { modes << mode; if (!selectedMode || selectedMode->refreshRate() < mode->refreshRate()) { selectedMode = mode; } } } Q_ASSERT(selectedMode); mOutput->setCurrentModeId(selectedMode->id()); // Don't remove the first "Auto" item - prevents ugly flicker of the combobox // when changing resolution for (int i = 1; i < mRefreshRate->count(); ++i) { mRefreshRate->removeItem(i); } for (int i = 0, total = modes.count(); i < total; ++i) { const KScreen::ModePtr mode = modes.at(i); mRefreshRate->addItem(i18n("%1 Hz", QLocale().toString(mode->refreshRate(), 'f', 2)), mode->id()); // If selected refresh rate is other then what we consider the "Auto" value // - that is it's not the highest resolution - then select it, otherwise // we stick with "Auto" if (mode == selectedMode && i > 1) { mRefreshRate->setCurrentIndex(i); } } Q_EMIT changed(); } void OutputConfig::slotRotationChanged(int index) { KScreen::Output::Rotation rotation = static_cast(mRotation->itemData(index).toInt()); mOutput->setRotation(rotation); Q_EMIT changed(); } void OutputConfig::slotRefreshRateChanged(int index) { QString modeId; if (index == 0) { // Item 0 is "Auto" - "Auto" is equal to highest refresh rate (at least // that's how I understand it, and since the combobox is sorted in descending // order, we just pick the second item from top modeId = mRefreshRate->itemData(1).toString(); } else { modeId = mRefreshRate->itemData(index).toString(); } mOutput->setCurrentModeId(modeId); Q_EMIT changed(); } void OutputConfig::slotScaleChanged(int index) { auto scale = mScale->itemData(index).toInt(); mOutput->setScale(scale); Q_EMIT changed(); } void OutputConfig::setShowScaleOption(bool showScaleOption) { mShowScaleOption = showScaleOption; if (mOutput) { initUi(); } } bool OutputConfig::showScaleOption() const { return mShowScaleOption; } diff --git a/kcm/src/resolutionslider.h b/kcm/src/resolutionslider.h index 4828214..504b479 100644 --- a/kcm/src/resolutionslider.h +++ b/kcm/src/resolutionslider.h @@ -1,63 +1,63 @@ /* * Copyright 2013 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef RESOLUTIONSLIDER_H #define RESOLUTIONSLIDER_H #include -#include +#include #include class QSlider; class QLabel; class QComboBox; class ResolutionSlider : public QWidget { Q_OBJECT public: explicit ResolutionSlider(const KScreen::OutputPtr &output, QWidget *parent = nullptr); ~ResolutionSlider() override; QSize currentResolution() const; Q_SIGNALS: void resolutionChanged(const QSize &size); private Q_SLOTS: void slotValueChanged(int); void slotOutputModeChanged(); private: KScreen::OutputPtr mOutput; QList mModes; QLabel *mSmallestLabel = nullptr; QLabel *mBiggestLabel = nullptr; QLabel *mCurrentLabel = nullptr; QSlider *mSlider = nullptr; QComboBox *mComboBox = nullptr; }; #endif // RESOLUTIONSLIDER_H diff --git a/kcm/src/utils.h b/kcm/src/utils.h index 198903a..f59c832 100644 --- a/kcm/src/utils.h +++ b/kcm/src/utils.h @@ -1,40 +1,40 @@ /* * Copyright 2013 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef KSCREEN_KCM_UTILS_H #define KSCREEN_KCM_UTILS_H -#include -#include +#include +#include #include #include namespace Utils { QString outputName(const KScreen::Output *output); QString outputName(const KScreen::OutputPtr &output); QString sizeToString(const QSize &size); } #endif diff --git a/kcm/src/widget.cpp b/kcm/src/widget.cpp index 50336f5..e4e1513 100644 --- a/kcm/src/widget.cpp +++ b/kcm/src/widget.cpp @@ -1,490 +1,490 @@ /* * Copyright (C) 2013 Daniel Vr??til * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "widget.h" #include "controlpanel.h" #ifdef WITH_PROFILES #include "profilesmodel.h" #endif #include "primaryoutputcombo.h" #include #include #include #include -#include +#include #include "declarative/qmloutput.h" #include "declarative/qmlscreen.h" #include "utils.h" #include "scalingconfig.h" #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #define QML_PATH "kcm_kscreen/qml/" Widget::Widget(QWidget *parent) : QWidget(parent) { qRegisterMetaType(); setMinimumHeight(550); QVBoxLayout *layout = new QVBoxLayout(this); QSplitter *splitter = new QSplitter(Qt::Vertical, this); layout->addWidget(splitter); mDeclarativeView = new QQuickWidget(); mDeclarativeView->setResizeMode(QQuickWidget::SizeRootObjectToView); mDeclarativeView->setMinimumHeight(280); splitter->addWidget(mDeclarativeView); QWidget *widget = new QWidget(this); splitter->addWidget(widget); splitter->setStretchFactor(1, 1); widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); QVBoxLayout *vbox = new QVBoxLayout(widget); const int topMargin = style()->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr, this); vbox->setContentsMargins(0, topMargin, 0, 0); widget->setLayout(vbox); QHBoxLayout *hbox = new QHBoxLayout; vbox->addLayout(hbox); mPrimaryCombo = new PrimaryOutputCombo(this); connect(mPrimaryCombo, &PrimaryOutputCombo::changed, this, &Widget::changed); mPrimaryLabel = new QLabel(i18n("Primary display:")); hbox->addWidget(mPrimaryLabel); hbox->addWidget(mPrimaryCombo); hbox->addStretch(); #ifdef WITH_PROFILES mProfilesModel = new ProfilesModel(this); connect(mProfilesModel, &ProfilesModel::modelUpdated()), this, &Widget::slotProfilesUpdated); mProfilesCombo = new QComboBox(this); mProfilesCombo->setModel(mProfilesModel); mProfilesCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); hbox->addWidget(new QLabel(i18n("Active profile"))); hbox->addWidget(mProfilesCombo); #endif mControlPanel = new ControlPanel(this); connect(mControlPanel, &ControlPanel::changed, this, &Widget::changed); vbox->addWidget(mControlPanel); mUnifyButton = new QPushButton(i18n("Unify Outputs"), this); connect(mUnifyButton, &QPushButton::released, [this]{ slotUnifyOutputs(); }); vbox->addWidget(mUnifyButton); mScaleAllOutputsButton = new QPushButton(i18n("Scale Display"), this); connect(mScaleAllOutputsButton, &QPushButton::released, [this] { QPointer dialog = new ScalingConfig(mConfig->outputs(), this); dialog->exec(); delete dialog; }); vbox->addWidget(mScaleAllOutputsButton); mOutputTimer = new QTimer(this); connect(mOutputTimer, &QTimer::timeout, this, &Widget::clearOutputIdentifiers); loadQml(); } Widget::~Widget() { clearOutputIdentifiers(); } bool Widget::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::Resize) { if (mOutputIdentifiers.contains(qobject_cast(object))) { QResizeEvent *e = static_cast(event); const QRect screenSize = object->property("screenSize").toRect(); QRect geometry(QPoint(0, 0), e->size()); geometry.moveCenter(screenSize.center()); static_cast(object)->setGeometry(geometry); // Pass the event further } } return QObject::eventFilter(object, event); } void Widget::setConfig(const KScreen::ConfigPtr &config) { if (mConfig) { KScreen::ConfigMonitor::instance()->removeConfig(mConfig); for (const KScreen::OutputPtr &output : mConfig->outputs()) { output->disconnect(this); } } mConfig = config; KScreen::ConfigMonitor::instance()->addConfig(mConfig); mScreen->setConfig(mConfig); mControlPanel->setConfig(mConfig); mPrimaryCombo->setConfig(mConfig); mUnifyButton->setEnabled(mConfig->outputs().count() > 1); mScaleAllOutputsButton->setVisible(!mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); mPrimaryCombo->setVisible(mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay)); mPrimaryLabel->setVisible(mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay)); for (const KScreen::OutputPtr &output : mConfig->outputs()) { connect(output.data(), &KScreen::Output::isEnabledChanged, this, &Widget::slotOutputEnabledChanged); connect(output.data(), &KScreen::Output::posChanged, this, &Widget::changed); } // Select the primary (or only) output by default QMLOutput *qmlOutput = mScreen->primaryOutput(); if (qmlOutput) { mScreen->setActiveOutput(qmlOutput); } else { if (!mScreen->outputs().isEmpty()) { mScreen->setActiveOutput(mScreen->outputs()[0]); } } slotOutputEnabledChanged(); } KScreen::ConfigPtr Widget::currentConfig() const { return mConfig; } void Widget::loadQml() { qmlRegisterType("org.kde.kscreen", 1, 0, "QMLOutput"); qmlRegisterType("org.kde.kscreen", 1, 0, "QMLScreen"); qmlRegisterType("org.kde.kscreen", 1, 0, "KScreenOutput"); qmlRegisterType("org.kde.kscreen", 1, 0, "KScreenEdid"); qmlRegisterType("org.kde.kscreen", 1, 0, "KScreenMode"); //const QString file = QDir::currentPath() + "/main.qml"; const QString file = QStandardPaths::locate(QStandardPaths::QStandardPaths::GenericDataLocation, QStringLiteral("kcm_kscreen/qml/main.qml")); mDeclarativeView->setSource(QUrl::fromLocalFile(file)); QQuickItem* rootObject = mDeclarativeView->rootObject(); mScreen = rootObject->findChild(QStringLiteral("outputView")); if (!mScreen) { return; } mScreen->setEngine(mDeclarativeView->engine()); connect(mScreen, &QMLScreen::focusedOutputChanged, this, &Widget::slotFocusedOutputChanged); connect(rootObject->findChild(QStringLiteral("identifyButton")), SIGNAL(clicked()), this, SLOT(slotIdentifyButtonClicked())); } void Widget::slotFocusedOutputChanged(QMLOutput *output) { mControlPanel->activateOutput(output->outputPtr()); } void Widget::slotOutputEnabledChanged() { int enabledOutputsCnt = 0; Q_FOREACH (const KScreen::OutputPtr &output, mConfig->outputs()) { if (output->isEnabled()) { ++enabledOutputsCnt; } if (enabledOutputsCnt > 1) { break; } } mUnifyButton->setEnabled(enabledOutputsCnt > 1); } void Widget::slotUnifyOutputs() { QMLOutput *base = mScreen->primaryOutput(); QList clones; if (!base) { Q_FOREACH (QMLOutput *output, mScreen->outputs()) { if (output->output()->isConnected() && output->output()->isEnabled()) { base = output; break; } } if (!base) { // WTF? return; } } if (base->isCloneMode()) { setConfig(mPrevConfig); mPrevConfig.clear(); mPrimaryCombo->setEnabled(true); mUnifyButton->setText(i18n("Unify Outputs")); } else { // Clone the current config, so that we can restore it in case user // breaks the cloning mPrevConfig = mConfig->clone(); Q_FOREACH (QMLOutput *output, mScreen->outputs()) { if (!output->output()->isConnected()) { continue; } if (!output->output()->isEnabled()) { output->setVisible(false); continue; } if (!base) { base = output; } output->setOutputX(0); output->setOutputY(0); output->output()->setPos(QPoint(0, 0)); output->output()->setClones(QList()); if (base != output) { clones << output->output()->id(); output->setCloneOf(base); output->setVisible(false); } } base->output()->setClones(clones); base->setIsCloneMode(true); mScreen->updateOutputsPlacement(); mPrimaryCombo->setEnabled(false); mControlPanel->setUnifiedOutput(base->outputPtr()); mUnifyButton->setText(i18n("Break Unified Outputs")); } Q_EMIT changed(); } void Widget::slotProfileChanged(int index) { #ifdef WITH_PROFILES const QVariantMap profile = mProfilesCombo->itemData(index, ProfilesModel::ProfileRole).toMap(); const QVariantList outputs = profile[QLatin1String("outputs")].toList(); // FIXME: Copy-pasted from KDED's Serializer::config() KScreen::Config *config = KScreen::Config::current(); KScreen::OutputList outputList = config->outputs(); Q_FOREACH(KScreen::Output * output, outputList) { if (!output->isConnected() && output->isEnabled()) { output->setEnabled(false); } } KScreen::Config *outputsConfig = config->clone(); Q_FOREACH(const QVariant & info, outputs) { KScreen::Output *output = findOutput(outputsConfig, info.toMap()); if (!output) { continue; } delete outputList.take(output->id()); outputList.insert(output->id(), output); } config->setOutputs(outputList); setConfig(config); #else Q_UNUSED(index) #endif } // FIXME: Copy-pasted from KDED's Serializer::findOutput() KScreen::OutputPtr Widget::findOutput(const KScreen::ConfigPtr &config, const QVariantMap &info) { KScreen::OutputList outputs = config->outputs(); Q_FOREACH(const KScreen::OutputPtr &output, outputs) { if (!output->isConnected()) { continue; } const QString outputId = (output->edid() && output->edid()->isValid()) ? output->edid()->hash() : output->name(); if (outputId != info[QStringLiteral("id")].toString()) { continue; } QVariantMap posInfo = info[QStringLiteral("pos")].toMap(); QPoint point(posInfo[QStringLiteral("x")].toInt(), posInfo[QStringLiteral("y")].toInt()); output->setPos(point); output->setPrimary(info[QStringLiteral("primary")].toBool()); output->setEnabled(info[QStringLiteral("enabled")].toBool()); output->setRotation(static_cast(info[QStringLiteral("rotation")].toInt())); QVariantMap modeInfo = info[QStringLiteral("mode")].toMap(); QVariantMap modeSize = modeInfo[QStringLiteral("size")].toMap(); QSize size(modeSize[QStringLiteral("width")].toInt(), modeSize[QStringLiteral("height")].toInt()); const KScreen::ModeList modes = output->modes(); Q_FOREACH(const KScreen::ModePtr &mode, modes) { if (mode->size() != size) { continue; } if (QString::number(mode->refreshRate()) != modeInfo[QStringLiteral("refresh")].toString()) { continue; } output->setCurrentModeId(mode->id()); break; } return output; } return KScreen::OutputPtr(); } void Widget::slotProfilesAboutToUpdate() { #ifdef WITH_PROFILES disconnect(mProfilesCombo, &QComboBox::currentIndexChanged, this, &Widget::slotProfileChanged); #endif } void Widget::slotProfilesUpdated() { #ifdef WITH_PROFILES connect(mProfilesCombo, &QComboBox::currentIndexChanged, this, &Widget::slotProfileChanged); const int index = mProfilesModel->activeProfileIndex(); mProfilesCombo->setCurrentIndex(index); #endif } void Widget::clearOutputIdentifiers() { mOutputTimer->stop(); qDeleteAll(mOutputIdentifiers); mOutputIdentifiers.clear(); } void Widget::slotIdentifyButtonClicked(bool checked) { Q_UNUSED(checked); connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, &Widget::slotIdentifyOutputs); } void Widget::slotIdentifyOutputs(KScreen::ConfigOperation *op) { if (op->hasError()) { return; } const KScreen::ConfigPtr config = qobject_cast(op)->config(); const QString qmlPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(QML_PATH "OutputIdentifier.qml")); mOutputTimer->stop(); clearOutputIdentifiers(); /* Obtain the current active configuration from KScreen */ Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { if (!output->isConnected() || !output->currentMode()) { continue; } const KScreen::ModePtr mode = output->currentMode(); QQuickView *view = new QQuickView(); view->setFlags(Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint); view->setResizeMode(QQuickView::SizeViewToRootObject); view->setSource(QUrl::fromLocalFile(qmlPath)); view->installEventFilter(this); QQuickItem *rootObj = view->rootObject(); if (!rootObj) { qWarning() << "Failed to obtain root item"; continue; } QSize deviceSize, logicalSize; if (output->isHorizontal()) { deviceSize = mode->size(); } else { deviceSize = QSize(mode->size().height(), mode->size().width()); } if (config->supportedFeatures() & KScreen::Config::Feature::PerOutputScaling) { // no scale adjustment needed on Wayland logicalSize = deviceSize; } else { logicalSize = deviceSize / devicePixelRatioF(); } rootObj->setProperty("outputName", Utils::outputName(output)); rootObj->setProperty("modeName", Utils::sizeToString(deviceSize)); view->setProperty("screenSize", QRect(output->pos(), logicalSize)); mOutputIdentifiers << view; } Q_FOREACH (QQuickView *view, mOutputIdentifiers) { view->show(); } mOutputTimer->start(2500); } diff --git a/tests/kded/serializertest.cpp b/tests/kded/serializertest.cpp index 22df6d9..7a61f6a 100644 --- a/tests/kded/serializertest.cpp +++ b/tests/kded/serializertest.cpp @@ -1,484 +1,484 @@ /************************************************************************************* * Copyright (C) 2015 by Daniel Vrátil * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "../../kded/serializer.h" #include -#include +#include #include #include #include #include #include using namespace KScreen; class TestSerializer : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testSimpleConfig(); void testTwoScreenConfig(); void testRotatedScreenConfig(); void testDisabledScreenConfig(); void testConfig404(); void testCorruptConfig(); void testCorruptEmptyConfig(); void testCorruptUselessConfig(); void testNullConfig(); void testIdenticalOutputs(); void testMoveConfig(); void testFixedConfig(); private: KScreen::ConfigPtr createConfig(bool output1Connected, bool output2Conected); }; ConfigPtr TestSerializer::createConfig(bool output1Connected, bool output2Connected) { KScreen::ScreenPtr screen = KScreen::ScreenPtr::create(); screen->setCurrentSize(QSize(1920, 1080)); screen->setMaxSize(QSize(32768, 32768)); screen->setMinSize(QSize(8, 8)); QList sizes({ QSize(320, 240), QSize(640, 480), QSize(1024, 768), QSize(1280, 1024), QSize(1920, 1280) }); KScreen::ModeList modes; for (int i = 0; i < sizes.count(); ++i) { const QSize &size = sizes[i]; KScreen::ModePtr mode = KScreen::ModePtr::create(); mode->setId(QStringLiteral("MODE-%1").arg(i)); mode->setName(QStringLiteral("%1x%2").arg(size.width()).arg(size.height())); mode->setSize(size); mode->setRefreshRate(60.0); modes.insert(mode->id(), mode); } KScreen::OutputPtr output1 = KScreen::OutputPtr::create(); output1->setId(1); output1->setName(QStringLiteral("OUTPUT-1")); output1->setPos(QPoint(0, 0)); output1->setConnected(output1Connected); output1->setEnabled(output1Connected); if (output1Connected) { output1->setModes(modes); } KScreen::OutputPtr output2 = KScreen::OutputPtr::create(); output2->setId(2); output2->setName(QStringLiteral("OUTPUT-2")); output2->setPos(QPoint(0, 0)); output2->setConnected(output2Connected); if (output2Connected) { output2->setModes(modes); } KScreen::ConfigPtr config = KScreen::ConfigPtr::create(); config->setScreen(screen); config->addOutput(output1); config->addOutput(output2); return config; } void TestSerializer::initTestCase() { qputenv("KSCREEN_LOGGING", "false"); Serializer::setConfigPath(QStringLiteral(TEST_DATA "/serializerdata/")); } void TestSerializer::testSimpleConfig() { KScreen::ConfigPtr config = createConfig(true, false); config = Serializer::config(config, QStringLiteral("simpleConfig.json")); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 1); auto output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->currentModeId(), QLatin1String("MODE-4")); QCOMPARE(output->currentMode()->size(), QSize(1920, 1280)); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->rotation(), KScreen::Output::None); QCOMPARE(output->pos(), QPoint(0, 0)); QCOMPARE(output->isPrimary(), true); auto screen = config->screen(); QCOMPARE(screen->currentSize(), QSize(1920, 1280)); } void TestSerializer::testTwoScreenConfig() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("twoScreenConfig.json")); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 2); auto output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->currentModeId(), QLatin1String("MODE-4")); QCOMPARE(output->currentMode()->size(), QSize(1920, 1280)); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->rotation(), KScreen::Output::None); QCOMPARE(output->pos(), QPoint(0, 0)); QCOMPARE(output->isPrimary(), true); output = config->connectedOutputs().last(); QCOMPARE(output->name(), QLatin1String("OUTPUT-2")); QCOMPARE(output->currentModeId(), QLatin1String("MODE-3")); QCOMPARE(output->currentMode()->size(), QSize(1280, 1024)); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->rotation(), KScreen::Output::None); QCOMPARE(output->pos(), QPoint(1920, 0)); QCOMPARE(output->isPrimary(), false); auto screen = config->screen(); QCOMPARE(screen->currentSize(), QSize(3200, 1280)); } void TestSerializer::testRotatedScreenConfig() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("rotatedScreenConfig.json")); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 2); auto output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->currentModeId(), QLatin1String("MODE-4")); QCOMPARE(output->currentMode()->size(), QSize(1920, 1280)); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->rotation(), KScreen::Output::None); QCOMPARE(output->pos(), QPoint(0, 0)); QCOMPARE(output->isPrimary(), true); output = config->connectedOutputs().last(); QCOMPARE(output->name(), QLatin1String("OUTPUT-2")); QCOMPARE(output->currentModeId(), QLatin1String("MODE-3")); QCOMPARE(output->currentMode()->size(), QSize(1280, 1024)); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->rotation(), KScreen::Output::Left); QCOMPARE(output->pos(), QPoint(1920, 0)); QCOMPARE(output->isPrimary(), false); auto screen = config->screen(); QCOMPARE(screen->currentSize(), QSize(2944, 1280)); } void TestSerializer::testDisabledScreenConfig() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("disabledScreenConfig.json")); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 2); auto output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->currentModeId(), QLatin1String("MODE-4")); QCOMPARE(output->currentMode()->size(), QSize(1920, 1280)); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->rotation(), KScreen::Output::None); QCOMPARE(output->pos(), QPoint(0, 0)); QCOMPARE(output->isPrimary(), true); output = config->connectedOutputs().last(); QCOMPARE(output->name(), QLatin1String("OUTPUT-2")); QCOMPARE(output->isEnabled(), false); auto screen = config->screen(); QCOMPARE(screen->currentSize(), QSize(1920, 1280)); } void TestSerializer::testConfig404() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("filenotfoundConfig.json")); QVERIFY(!config); QVERIFY(config.isNull()); } void TestSerializer::testCorruptConfig() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("corruptConfig.json")); QVERIFY(config); QCOMPARE(config->outputs().count(), 2); QVERIFY(config->isValid()); } void TestSerializer::testCorruptEmptyConfig() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("corruptEmptyConfig.json")); QVERIFY(config); QCOMPARE(config->outputs().count(), 2); QVERIFY(config->isValid()); } void TestSerializer::testCorruptUselessConfig() { KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("corruptUselessConfig.json")); QVERIFY(config); QCOMPARE(config->outputs().count(), 2); QVERIFY(config->isValid()); } void TestSerializer::testNullConfig() { KScreen::ConfigPtr nullConfig; QVERIFY(!nullConfig); // Null configs have empty configIds QVERIFY(Serializer::configId(nullConfig).isEmpty()); // Load config from a file not found results in a nullptr KScreen::ConfigPtr config = createConfig(true, true); QVERIFY(!Serializer::config(config, QString())); // Wrong config file name should fail to save QCOMPARE(Serializer::saveConfig(config, QString()), false); } void TestSerializer::testIdenticalOutputs() { // Test configuration of a video wall with 6 identical outputs connected // this is the autotest for https://bugs.kde.org/show_bug.cgi?id=325277 KScreen::ScreenPtr screen = KScreen::ScreenPtr::create(); screen->setCurrentSize(QSize(1920, 1080)); screen->setMaxSize(QSize(32768, 32768)); screen->setMinSize(QSize(8, 8)); QList sizes({ QSize(640, 480), QSize(1024, 768), QSize(1920, 1080), QSize(1280, 1024), QSize(1920, 1280) }); KScreen::ModeList modes; for (int i = 0; i < sizes.count(); ++i) { const QSize &size = sizes[i]; KScreen::ModePtr mode = KScreen::ModePtr::create(); mode->setId(QStringLiteral("MODE-%1").arg(i)); mode->setName(QStringLiteral("%1x%2").arg(size.width()).arg(size.height())); mode->setSize(size); mode->setRefreshRate(60.0); modes.insert(mode->id(), mode); } // This one is important, the output id in the config file is a hash of it QByteArray data = QByteArray::fromBase64("AP///////wAQrBbwTExLQQ4WAQOANCB46h7Frk80sSYOUFSlSwCBgKlA0QBxTwEBAQEBAQEBKDyAoHCwI0AwIDYABkQhAAAaAAAA/wBGNTI1TTI0NUFLTEwKAAAA/ABERUxMIFUyNDEwCiAgAAAA/QA4TB5REQAKICAgICAgAToCAynxUJAFBAMCBxYBHxITFCAVEQYjCQcHZwMMABAAOC2DAQAA4wUDAQI6gBhxOC1AWCxFAAZEIQAAHgEdgBhxHBYgWCwlAAZEIQAAngEdAHJR0B4gbihVAAZEIQAAHowK0Iog4C0QED6WAAZEIQAAGAAAAAAAAAAAAAAAAAAAPg=="); // When setting up the outputs, make sure they're not added in alphabetical order // or in the same order of the config file, as that makes the tests accidentally pass KScreen::OutputPtr output1 = KScreen::OutputPtr::create(); output1->setId(1); output1->setEdid(data); output1->setName(QStringLiteral("DisplayPort-0")); output1->setPos(QPoint(0, 0)); output1->setConnected(true); output1->setEnabled(false); output1->setModes(modes); KScreen::OutputPtr output2 = KScreen::OutputPtr::create(); output2->setId(2); output2->setEdid(data); output2->setName(QStringLiteral("DisplayPort-1")); output2->setPos(QPoint(0, 0)); output2->setConnected(true); output2->setEnabled(false); output2->setModes(modes); KScreen::OutputPtr output3 = KScreen::OutputPtr::create(); output3->setId(3); output3->setEdid(data); output3->setName(QStringLiteral("DisplayPort-2")); output3->setPos(QPoint(0, 0)); output3->setConnected(true); output3->setEnabled(false); output3->setModes(modes); KScreen::OutputPtr output6 = KScreen::OutputPtr::create(); output6->setId(6); output6->setEdid(data); output6->setName(QStringLiteral("DVI-0")); output6->setPos(QPoint(0, 0)); output6->setConnected(true); output6->setEnabled(false); output6->setModes(modes); KScreen::OutputPtr output4 = KScreen::OutputPtr::create(); output4->setId(4); output4->setEdid(data); output4->setName(QStringLiteral("DisplayPort-3")); output4->setPos(QPoint(0, 0)); output4->setConnected(true); output4->setEnabled(false); output4->setModes(modes); KScreen::OutputPtr output5 = KScreen::OutputPtr::create(); output5->setId(5); output5->setEdid(data); output5->setName(QStringLiteral("DVI-1")); output5->setPos(QPoint(0, 0)); output5->setConnected(true); output5->setEnabled(false); output5->setModes(modes); KScreen::ConfigPtr config = KScreen::ConfigPtr::create(); config->setScreen(screen); config->addOutput(output6); config->addOutput(output2); config->addOutput(output5); config->addOutput(output4); config->addOutput(output3); config->addOutput(output1); QHash positions; positions["DisplayPort-0"] = QPoint(0, 1080); positions["DisplayPort-1"] = QPoint(2100, 30); positions["DisplayPort-2"] = QPoint(2100, 1080); positions["DisplayPort-3"] = QPoint(4020, 0); positions["DVI-0"] = QPoint(4020, 1080); positions["DVI-1"] = QPoint(0, 0); config = Serializer::config(config, QStringLiteral("outputgrid_2x3.json")); QVERIFY(config); QCOMPARE(config->connectedOutputs().count(), 6); Q_FOREACH (auto output, config->connectedOutputs()) { QVERIFY(positions.keys().contains(output->name())); QVERIFY(output->name() != Serializer::outputId(output)); QCOMPARE(positions[output->name()], output->pos()); QCOMPARE(output->currentMode()->size(), QSize(1920, 1080)); QCOMPARE(output->currentMode()->refreshRate(), 60.0); QVERIFY(output->isEnabled()); } QCOMPARE(config->screen()->currentSize(), QSize(5940, 2160)); } void TestSerializer::testMoveConfig() { // Test if restoring a config using Serializer::moveConfig(src, dest) works // https://bugs.kde.org/show_bug.cgi?id=353029 // Load a dualhead config KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("twoScreenConfig.json")); QVERIFY(config); // Make sure we don't write into TEST_DATA QStandardPaths::setTestModeEnabled(true); Serializer::setConfigPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/")); // Basic assumptions for the remainder of our tests, this is the situation where the lid is opened QCOMPARE(config->connectedOutputs().count(), 2); auto output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), true); auto output2 = config->connectedOutputs().last(); QCOMPARE(output2->name(), QLatin1String("OUTPUT-2")); QCOMPARE(output2->isEnabled(), true); QCOMPARE(output2->isPrimary(), false); // we fake the lid being closed, first save our current config to _lidOpened Serializer::saveConfig(config, "0xdeadbeef_lidOpened"); // ... then switch off the panel, set primary to the other output output->setEnabled(false); output->setPrimary(false); output2->setPrimary(true); // save config as the current one, this is the config we don't want restored, and which we'll overwrite Serializer::saveConfig(config, "0xdeadbeef"); QCOMPARE(output->isEnabled(), false); QCOMPARE(output->isPrimary(), false); QCOMPARE(output2->isPrimary(), true); // Check if both files exist QFile openCfg(Serializer::configFileName("0xdeadbeef_lidOpened")); QFile closedCfg(Serializer::configFileName("0xdeadbeef")); QVERIFY(openCfg.exists()); QVERIFY(closedCfg.exists()); // Switcheroo... QVERIFY(Serializer::moveConfig("0xdeadbeef_lidOpened", "0xdeadbeef")); // Check actual files, src should be gone, dest must exist QVERIFY(!openCfg.exists()); QVERIFY(closedCfg.exists()); // Now load the resulting config and make sure the laptop panel is enabled and primary again config = Serializer::config(config, "0xdeadbeef"); output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), true); output2 = config->connectedOutputs().last(); QCOMPARE(output2->name(), QLatin1String("OUTPUT-2")); QCOMPARE(output2->isEnabled(), true); QCOMPARE(output2->isPrimary(), false); // Make sure we don't screw up when there's no _lidOpened config QVERIFY(!Serializer::moveConfig("0xdeadbeef_lidOpened", "0xdeadbeef")); config = Serializer::config(config, "0xdeadbeef"); output = config->connectedOutputs().first(); QCOMPARE(output->name(), QLatin1String("OUTPUT-1")); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), true); output2 = config->connectedOutputs().last(); QCOMPARE(output2->name(), QLatin1String("OUTPUT-2")); QCOMPARE(output2->isEnabled(), true); QCOMPARE(output2->isPrimary(), false); Serializer::setConfigPath(QStringLiteral(TEST_DATA "/serializerdata/")); } void TestSerializer::testFixedConfig() { // Load a dualhead config KScreen::ConfigPtr config = createConfig(true, true); config = Serializer::config(config, QStringLiteral("twoScreenConfig.json")); QVERIFY(config); // Make sure we don't write into TEST_DATA QStandardPaths::setTestModeEnabled(true); Serializer::setConfigPath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QStringLiteral("/kscreen/")); // save config as the current one, this is the config we don't want restored, and which we'll overwrite Serializer::saveConfig(config, Serializer::sFixedConfig); // Check if both files exist QFile fixedCfg(Serializer::configFileName(Serializer::sFixedConfig)); QVERIFY(fixedCfg.exists()); } QTEST_MAIN(TestSerializer) #include "serializertest.moc" diff --git a/tests/kded/testgenerator.cpp b/tests/kded/testgenerator.cpp index 7628ff9..87b87fa 100644 --- a/tests/kded/testgenerator.cpp +++ b/tests/kded/testgenerator.cpp @@ -1,472 +1,472 @@ /************************************************************************************* * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "../../kded/generator.h" #include -#include +#include #include #include #include using namespace KScreen; class testScreenConfig : public QObject { Q_OBJECT private: KScreen::ConfigPtr loadConfig(const QByteArray &fileName); void switchDisplayTwoScreensNoCommonMode(); private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void singleOutput(); void laptopLidOpenAndExternal(); void laptopLidOpenAndTwoExternal(); void laptopLidClosedAndExternal(); void laptopLidClosedAndThreeExternal(); void laptopDockedLidOpenAndExternal(); void laptopDockedLidClosedAndExternal(); void workstationWithoutScreens(); void workstationWithNoConnectedScreens(); void workstationTwoExternalSameSize(); void workstationFallbackMode(); void workstationTwoExternalDiferentSize(); void switchDisplayTwoScreens(); }; KScreen::ConfigPtr testScreenConfig::loadConfig(const QByteArray& fileName) { KScreen::BackendManager::instance()->shutdownBackend(); QByteArray path(TEST_DATA "configs/" + fileName); qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" + path); qDebug() << path; KScreen::GetConfigOperation *op = new KScreen::GetConfigOperation; if (!op->exec()) { qWarning() << op->errorString(); return ConfigPtr(); } return op->config(); } void testScreenConfig::initTestCase() { qputenv("KSCREEN_LOGGING", "false"); setenv("KSCREEN_BACKEND", "Fake", 1); } void testScreenConfig::cleanupTestCase() { KScreen::BackendManager::instance()->shutdownBackend(); } void testScreenConfig::singleOutput() { const ConfigPtr currentConfig = loadConfig("singleOutput.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr output = config->outputs().value(1); QCOMPARE(output->currentModeId(), QLatin1String("3")); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), true); QCOMPARE(output->pos(), QPoint(0,0)); } void testScreenConfig::laptopLidOpenAndExternal() { const ConfigPtr currentConfig = loadConfig("laptopAndExternal.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr laptop = config->outputs().value(1); OutputPtr external = config->outputs().value(2); QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0)); QCOMPARE(external->currentModeId(), QLatin1String("4")); QCOMPARE(external->isPrimary(), false); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(1280, 0)); } void testScreenConfig::laptopLidOpenAndTwoExternal() { const ConfigPtr currentConfig = loadConfig("laptopLidOpenAndTwoExternal.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr laptop = config->outputs().value(1); OutputPtr hdmi1 = config->outputs().value(2); OutputPtr hdmi2 = config->outputs().value(3); QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0)); QCOMPARE(hdmi1->currentModeId(), QLatin1String("4")); QCOMPARE(hdmi1->isPrimary(), false); QCOMPARE(hdmi1->isEnabled(), true); QCOMPARE(hdmi1->pos(), QPoint(hdmi2->pos().x() + hdmi2->currentMode()->size().width(), 0)); QCOMPARE(hdmi2->currentModeId(), QLatin1String("4")); QCOMPARE(hdmi2->isPrimary(), false); QCOMPARE(hdmi2->isEnabled(), true); QCOMPARE(hdmi2->pos(), QPoint(1280, 0)); } void testScreenConfig::laptopLidClosedAndExternal() { const ConfigPtr currentConfig = loadConfig("laptopAndExternal.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); generator->setForceLidClosed(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr laptop = config->outputs().value(1); OutputPtr external = config->outputs().value(2); QCOMPARE(laptop->isEnabled(), false); QCOMPARE(laptop->isPrimary(), false); QCOMPARE(external->currentModeId(), QLatin1String("4")); QCOMPARE(external->isPrimary(), true); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(0, 0)); } void testScreenConfig::laptopLidClosedAndThreeExternal() { const ConfigPtr currentConfig = loadConfig("laptopLidClosedAndThreeExternal.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); generator->setForceLidClosed(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr laptop = config->outputs().value(1); OutputPtr hdmi1 = config->outputs().value(2); OutputPtr hdmi2 = config->outputs().value(3); OutputPtr primary = config->outputs().value(4); QCOMPARE(laptop->isEnabled(), false); QCOMPARE(laptop->isPrimary(), false); QCOMPARE(hdmi1->isEnabled(), true); QCOMPARE(hdmi1->isPrimary(), false); QCOMPARE(hdmi1->currentModeId(), QLatin1String("4")); QCOMPARE(hdmi1->pos(), QPoint(primary->currentMode()->size().width(), 0)); QCOMPARE(hdmi2->isEnabled(), true); QCOMPARE(hdmi2->isPrimary(), false); QCOMPARE(hdmi2->currentModeId(), QLatin1String("3")); QCOMPARE(hdmi2->pos(), QPoint(hdmi1->pos().x() + hdmi1->currentMode()->size().width(), 0)); QCOMPARE(primary->isEnabled(), true); QCOMPARE(primary->isPrimary(), true); QCOMPARE(primary->currentModeId(), QLatin1String("4")); QCOMPARE(primary->pos(), QPoint(0,0)); } void testScreenConfig::laptopDockedLidOpenAndExternal() { const ConfigPtr currentConfig = loadConfig("laptopAndExternal.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); generator->setForceLidClosed(false); generator->setForceDocked(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr laptop = config->outputs().value(1); OutputPtr external = config->outputs().value(2); QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), false); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0)); QCOMPARE(external->currentModeId(), QLatin1String("4")); QCOMPARE(external->isPrimary(), true); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(1280, 0)); } void testScreenConfig::laptopDockedLidClosedAndExternal() { const ConfigPtr currentConfig = loadConfig("laptopAndExternal.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); generator->setForceLidClosed(true); generator->setForceDocked(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr laptop = config->outputs().value(1); OutputPtr external = config->outputs().value(2); QCOMPARE(laptop->isEnabled(), false); QCOMPARE(laptop->isPrimary(), false); QCOMPARE(external->currentModeId(), QLatin1String("4")); QCOMPARE(external->isPrimary(), true); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(0, 0)); } void testScreenConfig::workstationWithoutScreens() { const ConfigPtr currentConfig = loadConfig("workstationWithoutScreens.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(false); generator->setForceNotLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); QVERIFY(config->outputs().isEmpty()); } void testScreenConfig::workstationWithNoConnectedScreens() { const ConfigPtr currentConfig = loadConfig("workstationWithNoConnectedScreens.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(false); generator->setForceNotLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr external1 = config->output(1); OutputPtr external2 = config->output(2); QCOMPARE(external1->isEnabled(), false); QCOMPARE(external2->isEnabled(), false); } void testScreenConfig::workstationTwoExternalSameSize() { const ConfigPtr currentConfig = loadConfig("workstaionTwoExternalSameSize.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(false); generator->setForceNotLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr external1 = config->output(1); OutputPtr external2 = config->output(2); QCOMPARE(external1->isPrimary(), true); QCOMPARE(external1->isEnabled(), true); QCOMPARE(external1->currentModeId(), QLatin1String("3")); QCOMPARE(external1->pos(), QPoint(0 ,0)); QCOMPARE(external2->isPrimary(), false); QCOMPARE(external2->isEnabled(), true); QCOMPARE(external2->currentModeId(), QLatin1String("3")); QCOMPARE(external2->pos(), QPoint(external1->currentMode()->size().width() ,0)); } void testScreenConfig::workstationFallbackMode() { const ConfigPtr currentConfig = loadConfig("workstationFallbackMode.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(false); generator->setForceNotLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr external1 = config->output(1); OutputPtr external2 = config->output(2); QCOMPARE(external1->isPrimary(), true); QCOMPARE(external1->isEnabled(), true); QCOMPARE(external1->currentModeId(), QLatin1String("1")); QCOMPARE(external1->pos(), QPoint(0 ,0)); QCOMPARE(external2->isPrimary(), false); QCOMPARE(external2->isEnabled(), true); QCOMPARE(external2->currentModeId(), QLatin1String("1")); QCOMPARE(external2->pos(), QPoint(0 ,0)); } void testScreenConfig::workstationTwoExternalDiferentSize() { const ConfigPtr currentConfig = loadConfig("workstationTwoExternalDiferentSize.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(false); generator->setForceNotLaptop(true); ConfigPtr config = generator->idealConfig(currentConfig); OutputPtr external1 = config->output(1); OutputPtr external2 = config->output(2); QCOMPARE(external1->isPrimary(), false); QCOMPARE(external1->isEnabled(), true); QCOMPARE(external1->currentModeId(), QLatin1String("3")); QCOMPARE(external1->pos(), QPoint(external2->currentMode()->size().width() ,0)); QCOMPARE(external2->isPrimary(), true); QCOMPARE(external2->isEnabled(), true); QCOMPARE(external2->currentModeId(), QLatin1String("4")); } void testScreenConfig::switchDisplayTwoScreens() { const ConfigPtr currentConfig = loadConfig("switchDisplayTwoScreens.json"); QVERIFY(currentConfig); Generator* generator = Generator::self(); generator->setCurrentConfig(currentConfig); generator->setForceLaptop(true); generator->setForceNotLaptop(false); generator->setForceDocked(false); generator->setForceLidClosed(false); //Clone all ConfigPtr config = generator->displaySwitch(Generator::Clone); OutputPtr laptop = config->outputs().value(1); OutputPtr external = config->outputs().value(2); QCOMPARE(laptop->currentModeId(), QLatin1String("2")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0)); QCOMPARE(external->currentModeId(), QLatin1String("3")); QCOMPARE(external->isPrimary(), false); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(0, 0)); //Extend to left config = generator->displaySwitch(Generator::ExtendToLeft); laptop = config->outputs().value(1); external = config->outputs().value(2); QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(1920, 0)); QCOMPARE(external->currentModeId(), QLatin1String("5")); QCOMPARE(external->isPrimary(), false); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(0, 0)); //Disable embedded,. enable external config = generator->displaySwitch(Generator::TurnOffEmbedded); laptop = config->outputs().value(1); external = config->outputs().value(2);; QCOMPARE(laptop->isEnabled(), false); QCOMPARE(external->currentModeId(), QLatin1String("5")); QCOMPARE(external->isPrimary(), true); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(0, 0)); //Enable embedded, disable external config = generator->displaySwitch(Generator::TurnOffExternal); laptop = config->outputs().value(1); external = config->outputs().value(2);; QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0));; QCOMPARE(external->isEnabled(), false); //Extend to right config = generator->displaySwitch(Generator::ExtendToRight); laptop = config->outputs().value(1); external = config->outputs().value(2); QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0)); QCOMPARE(external->currentModeId(),QLatin1String("5")); QCOMPARE(external->isPrimary(), false); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(1280, 0)); } void testScreenConfig::switchDisplayTwoScreensNoCommonMode() { const ConfigPtr currentConfig = loadConfig("switchDisplayTwoScreensNoCommonMode.json"); QVERIFY(currentConfig); Generator *generator = Generator::self(); generator->setCurrentConfig(currentConfig); qDebug() << "MEH MOH"; ConfigPtr config = generator->displaySwitch(Generator::Clone); OutputPtr laptop = config->outputs().value(1); OutputPtr external = config->outputs().value(2); QCOMPARE(laptop->currentModeId(), QLatin1String("3")); QCOMPARE(laptop->isPrimary(), true); QCOMPARE(laptop->isEnabled(), true); QCOMPARE(laptop->pos(), QPoint(0, 0)); QCOMPARE(external->currentModeId(), QLatin1String("5")); QCOMPARE(external->isPrimary(), false); QCOMPARE(external->isEnabled(), true); QCOMPARE(external->pos(), QPoint(0, 0)); } QTEST_MAIN(testScreenConfig) #include "testgenerator.moc"