diff --git a/kcm/src/kcm_kscreen.cpp b/kcm/src/kcm_kscreen.cpp --- a/kcm/src/kcm_kscreen.cpp +++ b/kcm/src/kcm_kscreen.cpp @@ -117,6 +117,8 @@ return; } + mKScreenWidget->save(); + const KScreen::ConfigPtr &config = mKScreenWidget->currentConfig(); bool atLeastOneEnabledOutput = false; @@ -182,6 +184,11 @@ qCDebug(KSCREEN_KCM) << "LOAD"; connect(new GetConfigOperation(), &GetConfigOperation::finished, this, &KCMKScreen::configReady); + if (!mKScreenWidget) { + return; + } + + mKScreenWidget->load(); } #include "kcm_kscreen.moc" diff --git a/kcm/src/widget.h b/kcm/src/widget.h --- a/kcm/src/widget.h +++ b/kcm/src/widget.h @@ -46,12 +46,27 @@ Q_OBJECT public: + //Keep in sync with generator.h + enum DisplaySwitchAction { + None = 0, + Clone = 1, + ExtendToLeft = 2, + TurnOffEmbedded = 3, + TurnOffExternal = 4, + ExtendToRight = 5, + }; + Q_ENUM(DisplaySwitchAction) + explicit Widget(QWidget *parent = nullptr); virtual ~Widget(); void setConfig(const KScreen::ConfigPtr &config); KScreen::ConfigPtr currentConfig() const; + + void load(); + void save(); + protected: bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; @@ -80,6 +95,8 @@ KScreen::OutputPtr findOutput(const KScreen::ConfigPtr &config, const QVariantMap &info); private: + + QMLScreen *mScreen = nullptr; KScreen::ConfigPtr mConfig; KScreen::ConfigPtr mPrevConfig; @@ -97,7 +114,8 @@ QList mOutputIdentifiers; QTimer *mOutputTimer = nullptr; - + QComboBox *mDefaultActionWhenUnknownMonitorPlugged = nullptr; }; + #endif // WIDGET_H diff --git a/kcm/src/widget.cpp b/kcm/src/widget.cpp --- a/kcm/src/widget.cpp +++ b/kcm/src/widget.cpp @@ -48,8 +48,11 @@ #include #include #include +#include +#include #define QML_PATH "kcm_kscreen/qml/" +Q_DECLARE_METATYPE(Widget::DisplaySwitchAction) Widget::Widget(QWidget *parent): QWidget(parent), @@ -130,11 +133,32 @@ vbox->addWidget(mScaleAllOutputsButton); + QHBoxLayout *unknownMonitorActionLayout = new QHBoxLayout; + unknownMonitorActionLayout->setMargin(0); + vbox->addLayout(unknownMonitorActionLayout); + + QLabel *unknownMonitorActionLabel = new QLabel(i18n("Default Action:"), this); + unknownMonitorActionLabel->setObjectName(QStringLiteral("unknownMonitorActionLabel")); + unknownMonitorActionLayout->addWidget(unknownMonitorActionLabel); + + mDefaultActionWhenUnknownMonitorPlugged = new QComboBox(this); + mDefaultActionWhenUnknownMonitorPlugged->setObjectName(QStringLiteral("defaultactioncombobox")); + connect(mDefaultActionWhenUnknownMonitorPlugged, static_cast(&QComboBox::currentIndexChanged), + this, &Widget::changed); + + unknownMonitorActionLayout->addWidget(mDefaultActionWhenUnknownMonitorPlugged); + + mDefaultActionWhenUnknownMonitorPlugged->addItem(i18n("None"), DisplaySwitchAction::None); + mDefaultActionWhenUnknownMonitorPlugged->addItem(i18n("Clone"), DisplaySwitchAction::Clone); + mDefaultActionWhenUnknownMonitorPlugged->addItem(i18n("Extend to Right"), DisplaySwitchAction::ExtendToRight); + mDefaultActionWhenUnknownMonitorPlugged->addItem(i18n("Extend to Left"), DisplaySwitchAction::ExtendToLeft); + mOutputTimer = new QTimer(this); connect(mOutputTimer, &QTimer::timeout, this, &Widget::clearOutputIdentifiers); loadQml(); + load(); } Widget::~Widget() @@ -203,6 +227,28 @@ return mConfig; } +void Widget::load() +{ + KConfig config(QStringLiteral("kscreenrc")); + KConfigGroup group = config.group("General"); + + const DisplaySwitchAction act = static_cast(group.readEntry("DisplayUnknownScreenAction", (int)ExtendToRight)); + const int index = mDefaultActionWhenUnknownMonitorPlugged->findData(act); + if (index != -1) { + mDefaultActionWhenUnknownMonitorPlugged->setCurrentIndex(index); + } else { + mDefaultActionWhenUnknownMonitorPlugged->setCurrentIndex(2); + } +} + +void Widget::save() +{ + KConfig config(QStringLiteral("kscreenrc")); + KConfigGroup group = config.group("General"); + + group.writeEntry("DisplayUnknownScreenAction", (int)mDefaultActionWhenUnknownMonitorPlugged->currentData().value()); +} + void Widget::loadQml() { qmlRegisterType("org.kde.kscreen", 1, 0, "QMLOutput"); diff --git a/kded/generator.h b/kded/generator.h --- a/kded/generator.h +++ b/kded/generator.h @@ -69,7 +69,9 @@ void cloneScreens(KScreen::OutputList &connectedOutputs); void laptop(KScreen::OutputList &connectedOutputs); void singleOutput(KScreen::OutputList &connectedOutputs); + void extendToRight(KScreen::OutputList &connectedOutputs); + void extendToLeft(KScreen::OutputList &connectedOutputs); KScreen::ModePtr bestModeForSize(const KScreen::ModeList& modes, const QSize &size); KScreen::ModePtr bestModeForOutput(const KScreen::OutputPtr &output); diff --git a/kded/generator.cpp b/kded/generator.cpp --- a/kded/generator.cpp +++ b/kded/generator.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include @@ -116,9 +118,34 @@ return fallbackIfNeeded(config); } - qCDebug(KSCREEN_KDED) << "Extend to Right"; - extendToRight(connectedOutputs); - + KConfig configKScreen(QStringLiteral("kscreenrc")); + KConfigGroup group = configKScreen.group("General"); + const DisplaySwitchAction act = static_cast(group.readEntry("DisplayUnknownScreenAction", (int)ExtendToRight)); + switch(act) { + case None: + qCDebug(KSCREEN_KDED) << "Nothing"; + break; + case Clone: + qCDebug(KSCREEN_KDED) << "Clone screen"; + cloneScreens(connectedOutputs); + break; + case ExtendToLeft: + qCDebug(KSCREEN_KDED) << "Extend to Left"; + extendToLeft(connectedOutputs); + break; + case ExtendToRight: + qCDebug(KSCREEN_KDED) << "Extend to Right"; + extendToRight(connectedOutputs); + break; + case TurnOffEmbedded: + case TurnOffExternal: + Q_UNREACHABLE(); + default: + qCDebug(KSCREEN_KDED) << "Fallback to Extend to Right"; + //Default: + extendToRight(connectedOutputs); + break; + } return fallbackIfNeeded(config); } @@ -504,6 +531,41 @@ } } +void Generator::extendToLeft(KScreen::OutputList &connectedOutputs) +{ + ASSERT_OUTPUTS(connectedOutputs); + if (connectedOutputs.isEmpty()) { + return; + } + + qCDebug(KSCREEN_KDED) << "Extending to the left"; + KScreen::OutputPtr biggest = biggestOutput(connectedOutputs); + Q_ASSERT(biggest); + + connectedOutputs.remove(biggest->id()); + + + int globalWidth = 0; + + Q_FOREACH(KScreen::OutputPtr output, connectedOutputs) { + output->setEnabled(true); + output->setPrimary(false); + output->setPos(QPoint(globalWidth, 0)); + const KScreen::ModePtr mode = bestModeForOutput(output); + Q_ASSERT(mode); + output->setCurrentModeId(mode->id()); + + globalWidth += output->geometry().width(); + } + + biggest->setEnabled(true); + biggest->setPrimary(true); + biggest->setPos(QPoint(globalWidth ,0)); + const KScreen::ModePtr mode = bestModeForOutput(biggest); + Q_ASSERT(mode); + biggest->setCurrentModeId(mode->id()); +} + KScreen::ModePtr Generator::biggestMode(const KScreen::ModeList &modes) { Q_ASSERT(!modes.isEmpty()); diff --git a/tests/kded/CMakeLists.txt b/tests/kded/CMakeLists.txt --- a/tests/kded/CMakeLists.txt +++ b/tests/kded/CMakeLists.txt @@ -20,7 +20,7 @@ add_executable(${testname} ${test_SRCS}) add_dependencies(${testname} kscreen) # make sure the dbus interfaces are generated target_compile_definitions(${testname} PRIVATE "-DTEST_DATA=\"${CMAKE_CURRENT_SOURCE_DIR}/\"") - target_link_libraries(${testname} Qt5::Test Qt5::DBus Qt5::Gui KF5::Screen) + target_link_libraries(${testname} Qt5::Test Qt5::DBus Qt5::Gui KF5::Screen KF5::ConfigCore) add_test(kscreen-kded-${testname} ${testname}) ecm_mark_as_test(${testname}) endmacro()