diff --git a/kcm/src/CMakeLists.txt b/kcm/src/CMakeLists.txt index 9cc944b..1edf523 100644 --- a/kcm/src/CMakeLists.txt +++ b/kcm/src/CMakeLists.txt @@ -1,51 +1,51 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kcm_displayconfiguration\") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/declarative") set(kcm_kscreen_SRCS declarative/qmloutput.cpp declarative/qmloutputcomponent.cpp declarative/qmlscreen.cpp collapsablebutton.cpp controlpanel.cpp outputconfig.cpp unifiedoutputconfig.cpp resolutionslider.cpp utils.cpp widget.cpp previewwidget.cpp scalingconfig.cpp ) ecm_qt_declare_logging_category(kcm_kscreen_SRCS HEADER kcm_screen_debug.h IDENTIFIER KSCREEN_KCM CATEGORY_NAME kscreen.kcm) -ki18n_wrap_ui(kcm_kscreen_SRCS stylepreview.ui scaling.ui) +ki18n_wrap_ui(kcm_kscreen_SRCS kscreen_widget.ui stylepreview.ui scaling.ui) add_library(kcm_kscreen MODULE kcm_kscreen.cpp ${kcm_kscreen_SRCS}) target_link_libraries(kcm_kscreen Qt5::QuickWidgets Qt5::Widgets KF5::Screen KF5::I18n KF5::ConfigCore KF5::ConfigWidgets KF5::WidgetsAddons ) install(TARGETS kcm_kscreen DESTINATION ${KDE_INSTALL_PLUGINDIR} ) add_executable(kcm_testapp kcm_testapp.cpp ${kcm_kscreen_SRCS}) set_target_properties(kcm_testapp PROPERTIES COMPILE_FLAGS "-DQT_DECLARATIVE_DEBUG") target_link_libraries(kcm_testapp Qt5::QuickWidgets Qt5::Widgets KF5::CoreAddons KF5::I18n KF5::ConfigCore KF5::Screen KF5::WidgetsAddons ) diff --git a/kcm/src/controlpanel.cpp b/kcm/src/controlpanel.cpp index d176383..8dc2ead 100644 --- a/kcm/src/controlpanel.cpp +++ b/kcm/src/controlpanel.cpp @@ -1,125 +1,125 @@ /* * 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 "controlpanel.h" #include "outputconfig.h" #include "unifiedoutputconfig.h" #include "kcm_screen_debug.h" #include #include ControlPanel::ControlPanel(QWidget *parent) : QFrame(parent) , mUnifiedOutputCfg(nullptr) { - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); mLayout = new QVBoxLayout(this); } ControlPanel::~ControlPanel() { } void ControlPanel::setConfig(const KScreen::ConfigPtr &config) { qDeleteAll(mOutputConfigs); mOutputConfigs.clear(); delete mUnifiedOutputCfg; mUnifiedOutputCfg = nullptr; if (mConfig) { mConfig->disconnect(this); } mConfig = config; connect(mConfig.data(), &KScreen::Config::outputAdded, this, &ControlPanel::addOutput); connect(mConfig.data(), &KScreen::Config::outputRemoved, this, &ControlPanel::removeOutput); for (const KScreen::OutputPtr &output : mConfig->outputs()) { addOutput(output); } } void ControlPanel::addOutput(const KScreen::OutputPtr &output) { OutputConfig *outputCfg = new OutputConfig(this); outputCfg->setVisible(false); outputCfg->setShowScaleOption(mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); outputCfg->setOutput(output); connect(outputCfg, &OutputConfig::changed, this, &ControlPanel::changed); mLayout->addWidget(outputCfg); mOutputConfigs << outputCfg; } void ControlPanel::removeOutput(int outputId) { for (OutputConfig *outputCfg : mOutputConfigs) { if (outputCfg->output()->id() == outputId) { mOutputConfigs.removeOne(outputCfg); delete outputCfg; return; } } } void ControlPanel::activateOutput(const KScreen::OutputPtr &output) { // Ignore activateOutput when in unified mode if (mUnifiedOutputCfg) { return; } qCDebug(KSCREEN_KCM) << "Activate output" << output->id(); Q_FOREACH (OutputConfig *cfg, mOutputConfigs) { cfg->setVisible(cfg->output()->id() == output->id()); } } void ControlPanel::setUnifiedOutput(const KScreen::OutputPtr &output) { Q_FOREACH (OutputConfig *config, mOutputConfigs) { if (!config->output()->isConnected()) { continue; } config->setVisible(output == nullptr); } if (output.isNull()) { mUnifiedOutputCfg->deleteLater(); mUnifiedOutputCfg = nullptr; } else { mUnifiedOutputCfg = new UnifiedOutputConfig(mConfig, this); mUnifiedOutputCfg->setOutput(output); mUnifiedOutputCfg->setVisible(true); mLayout->insertWidget(mLayout->count() - 2, mUnifiedOutputCfg); connect(mUnifiedOutputCfg, &UnifiedOutputConfig::changed, this, &ControlPanel::changed); } } diff --git a/kcm/src/kscreen_widget.ui b/kcm/src/kscreen_widget.ui new file mode 100644 index 0000000..78c337f --- /dev/null +++ b/kcm/src/kscreen_widget.ui @@ -0,0 +1,101 @@ + + + KScreenWidget + + + + 0 + 0 + 549 + 591 + + + + + 0 + 0 + + + + + 100 + 100 + + + + Form + + + + + + + 0 + 0 + + + + QQuickWidget::SizeRootObjectToView + + + + + + + + + Primary display: + + + + + + + QComboBox::AdjustToContents + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Unify Outputs + + + + + + + Scale Display + + + + + + + + QQuickWidget + QWidget +
QtQuickWidgets/QQuickWidget
+
+
+ + +
diff --git a/kcm/src/outputconfig.cpp b/kcm/src/outputconfig.cpp index c02a11c..df7206f 100644 --- a/kcm/src/outputconfig.cpp +++ b/kcm/src/outputconfig.cpp @@ -1,263 +1,261 @@ /* * 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 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); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 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/widget.cpp b/kcm/src/widget.cpp index 4d7fcb1..3010a9e 100644 --- a/kcm/src/widget.cpp +++ b/kcm/src/widget.cpp @@ -1,591 +1,555 @@ /* * 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 #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 "ui_kscreen_widget.h" + #define QML_PATH "kcm_kscreen/qml/" Widget::Widget(QWidget *parent) : QWidget(parent) + , ui(new Ui::KScreenWidget()) { 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 QComboBox(this); - mPrimaryCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); - mPrimaryCombo->addItem(i18n("No Primary Output")); - connect(mPrimaryCombo, QOverload::of(&QComboBox::currentIndexChanged), + ui->setupUi(this); + ui->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + connect(ui->primaryCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &Widget::primaryOutputSelected); - 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); + ui->controlPanelLayout->addWidget(mControlPanel); - mUnifyButton = new QPushButton(i18n("Unify Outputs"), this); - connect(mUnifyButton, &QPushButton::released, + connect(ui->unifyButton, &QPushButton::released, [this]{ slotUnifyOutputs(); }); - vbox->addWidget(mUnifyButton); - - mScaleAllOutputsButton = new QPushButton(i18n("Scale Display"), this); - connect(mScaleAllOutputsButton, &QPushButton::released, + connect(ui->scaleAllOutputsButton, &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->disconnect(this); } mConfig = config; KScreen::ConfigMonitor::instance()->addConfig(mConfig); resetPrimaryCombo(); connect(mConfig.data(), &KScreen::Config::outputAdded, this, &Widget::outputAdded); connect(mConfig.data(), &KScreen::Config::outputRemoved, this, &Widget::outputRemoved); connect(mConfig.data(), &KScreen::Config::primaryOutputChanged, this, &Widget::primaryOutputChanged); mScreen->setConfig(mConfig); mControlPanel->setConfig(mConfig); - mUnifyButton->setEnabled(mConfig->outputs().count() > 1); - mScaleAllOutputsButton->setVisible(!mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); + ui->unifyButton->setEnabled(mConfig->outputs().count() > 1); + ui->scaleAllOutputsButton->setVisible(!mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); for (const KScreen::OutputPtr &output : mConfig->outputs()) { outputAdded(output); } // 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().at(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)); + ui->quickWidget->setSource(QUrl::fromLocalFile(file)); - QQuickItem* rootObject = mDeclarativeView->rootObject(); + QQuickItem* rootObject = ui->quickWidget->rootObject(); mScreen = rootObject->findChild(QStringLiteral("outputView")); if (!mScreen) { return; } - mScreen->setEngine(mDeclarativeView->engine()); + mScreen->setEngine(ui->quickWidget->engine()); connect(mScreen, &QMLScreen::focusedOutputChanged, this, &Widget::slotFocusedOutputChanged); connect(rootObject->findChild(QStringLiteral("identifyButton")), SIGNAL(clicked()), this, SLOT(slotIdentifyButtonClicked())); } void Widget::resetPrimaryCombo() { bool isPrimaryDisplaySupported = mConfig->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay); - mPrimaryLabel->setVisible(isPrimaryDisplaySupported); - mPrimaryCombo->setVisible(isPrimaryDisplaySupported); + ui->primaryLabel->setVisible(isPrimaryDisplaySupported); + ui->primaryCombo->setVisible(isPrimaryDisplaySupported); // Don't emit currentIndexChanged when resetting - bool blocked = mPrimaryCombo->blockSignals(true); - mPrimaryCombo->clear(); - mPrimaryCombo->addItem(i18n("No Primary Output")); - mPrimaryCombo->blockSignals(blocked); + bool blocked = ui->primaryCombo->blockSignals(true); + ui->primaryCombo->clear(); + ui->primaryCombo->addItem(i18n("No Primary Output")); + ui->primaryCombo->blockSignals(blocked); if (!mConfig) { return; } for (auto &output: mConfig->outputs()) { addOutputToPrimaryCombo(output); } } void Widget::addOutputToPrimaryCombo(const KScreen::OutputPtr &output) { if (!output->isConnected() || !output->isEnabled()) { return; } - mPrimaryCombo->addItem(Utils::outputName(output), output->id()); + ui->primaryCombo->addItem(Utils::outputName(output), output->id()); if (output->isPrimary()) { Q_ASSERT(mConfig); - int lastIndex = mPrimaryCombo->count() - 1; - mPrimaryCombo->setCurrentIndex(lastIndex); + int lastIndex = ui->primaryCombo->count() - 1; + ui->primaryCombo->setCurrentIndex(lastIndex); } } void Widget::slotFocusedOutputChanged(QMLOutput *output) { mControlPanel->activateOutput(output->outputPtr()); } void Widget::slotOutputEnabledChanged() { resetPrimaryCombo(); int enabledOutputsCount = 0; Q_FOREACH (const KScreen::OutputPtr &output, mConfig->outputs()) { if (output->isEnabled()) { ++enabledOutputsCount; } if (enabledOutputsCount > 1) { break; } } - mUnifyButton->setEnabled(enabledOutputsCount > 1); + ui->unifyButton->setEnabled(enabledOutputsCount > 1); } void Widget::slotOutputConnectedChanged() { resetPrimaryCombo(); } void Widget::slotUnifyOutputs() { QMLOutput *base = mScreen->primaryOutput(); QList clones; if (!base) { for (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")); + ui->primaryCombo->setEnabled(true); + ui->unifyButton->setText(i18n("Unify Outputs")); } else { // Clone the current config, so that we can restore it in case user // breaks the cloning mPrevConfig = mConfig->clone(); for (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); + ui->primaryCombo->setEnabled(false); mControlPanel->setUnifiedOutput(base->outputPtr()); - - mUnifyButton->setText(i18n("Break Unified Outputs")); + ui->unifyButton->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(); for (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::outputAdded(const KScreen::OutputPtr &output) { connect(output.data(), &KScreen::Output::isConnectedChanged, this, &Widget::slotOutputConnectedChanged); connect(output.data(), &KScreen::Output::isEnabledChanged, this, &Widget::slotOutputEnabledChanged); connect(output.data(), &KScreen::Output::posChanged, this, &Widget::changed); addOutputToPrimaryCombo(output); } void Widget::outputRemoved(int outputId) { KScreen::OutputPtr output = mConfig->output(outputId); if (!output.isNull()) { output->disconnect(this); } - const int index = mPrimaryCombo->findData(outputId); + const int index = ui->primaryCombo->findData(outputId); if (index == -1) { return; } - if (index == mPrimaryCombo->currentIndex()) { + if (index == ui->primaryCombo->currentIndex()) { // We'll get the actual primary update signal eventually // Don't emit currentIndexChanged - const bool blocked = mPrimaryCombo->blockSignals(true); - mPrimaryCombo->setCurrentIndex(0); - mPrimaryCombo->blockSignals(blocked); + const bool blocked = ui->primaryCombo->blockSignals(true); + ui->primaryCombo->setCurrentIndex(0); + ui->primaryCombo->blockSignals(blocked); } - mPrimaryCombo->removeItem(index); + ui->primaryCombo->removeItem(index); } void Widget::primaryOutputSelected(int index) { if (!mConfig) { return; } - const KScreen::OutputPtr newPrimary = index == 0 ? KScreen::OutputPtr() : mConfig->output(mPrimaryCombo->itemData(index).toInt()); + const KScreen::OutputPtr newPrimary = index == 0 ? KScreen::OutputPtr() : mConfig->output(ui->primaryCombo->itemData(index).toInt()); if (newPrimary == mConfig->primaryOutput()) { return; } mConfig->setPrimaryOutput(newPrimary); Q_EMIT changed(); } void Widget::primaryOutputChanged(const KScreen::OutputPtr &output) { Q_ASSERT(mConfig); - int index = output.isNull() ? 0 : mPrimaryCombo->findData(output->id()); - if (index == -1 || index == mPrimaryCombo->currentIndex()) { + int index = output.isNull() ? 0 : ui->primaryCombo->findData(output->id()); + if (index == -1 || index == ui->primaryCombo->currentIndex()) { return; } - mPrimaryCombo->setCurrentIndex(index); + ui->primaryCombo->setCurrentIndex(index); } 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; } for (QQuickView *view: mOutputIdentifiers) { view->show(); } mOutputTimer->start(2500); } diff --git a/kcm/src/widget.h b/kcm/src/widget.h index c5b94ae..999dd63 100644 --- a/kcm/src/widget.h +++ b/kcm/src/widget.h @@ -1,113 +1,112 @@ /* * 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. * */ #ifndef WIDGET_H #define WIDGET_H #include #include #include class ProfilesModel; class QLabel; class QMLOutput; class QMLScreen; class ControlPanel; class PrimaryOutputCombo; class QPushButton; class QComboBox; class QQuickView; class QQuickWidget; namespace KScreen { class ConfigOperation; } +namespace Ui +{ +class KScreenWidget; +} + class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget() override; void setConfig(const KScreen::ConfigPtr &config); KScreen::ConfigPtr currentConfig() const; protected: bool eventFilter(QObject *object, QEvent *event) override; Q_SIGNALS: void changed(); private Q_SLOTS: void slotFocusedOutputChanged(QMLOutput *output); void slotOutputEnabledChanged(); void slotOutputConnectedChanged(); void slotUnifyOutputs(); void slotProfileChanged(int index); void slotProfilesAboutToUpdate(); void slotProfilesUpdated(); void slotIdentifyButtonClicked(bool checked = true); void slotIdentifyOutputs(KScreen::ConfigOperation *op); void clearOutputIdentifiers(); void outputAdded(const KScreen::OutputPtr &output); void outputRemoved(int outputId); void primaryOutputSelected(int index); void primaryOutputChanged(const KScreen::OutputPtr &output); private: void loadQml(); void resetPrimaryCombo(); void addOutputToPrimaryCombo(const KScreen::OutputPtr &output); KScreen::OutputPtr findOutput(const KScreen::ConfigPtr &config, const QVariantMap &info); private: + Ui::KScreenWidget *ui; QMLScreen *mScreen = nullptr; KScreen::ConfigPtr mConfig = nullptr; KScreen::ConfigPtr mPrevConfig = nullptr; - QQuickWidget *mDeclarativeView = nullptr; ControlPanel *mControlPanel = nullptr; ProfilesModel *mProfilesModel = nullptr; - QComboBox *mPrimaryCombo = nullptr; - QLabel *mPrimaryLabel = nullptr; QComboBox *mProfilesCombo = nullptr; - - QPushButton *mScaleAllOutputsButton = nullptr; - QPushButton *mUnifyButton = nullptr; QPushButton *mSaveProfileButton = nullptr; QList mOutputIdentifiers; QTimer *mOutputTimer = nullptr; - }; #endif // WIDGET_H