File indexing completed on 2024-04-28 05:27:37

0001 /*
0002     SPDX-FileCopyrightText: 2016 Sebastian Kügler <sebas@kde.org>
0003 
0004     Work sponsored by the LiMux project of the city of Munich:
0005     SPDX-FileCopyrightText: 2018 Kai Uwe Broulik <kde@broulik.de>
0006 
0007     SPDX-FileCopyrightText: 2022 David Redondo <kde@david-redondo.de>
0008     SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>
0009 
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 */
0012 
0013 #include "osdaction.h"
0014 
0015 #include <KLocalizedString>
0016 #include <KScreen/Config>
0017 #include <KScreen/Mode>
0018 #include <KScreen/Output>
0019 #include <KScreen/SetConfigOperation>
0020 #include <QPoint>
0021 
0022 using namespace KScreen;
0023 
0024 QList<OsdAction> OsdAction::availableActions()
0025 {
0026     return {
0027         {SwitchToExternal, i18nd("kscreen_common", "Switch to external screen"), QStringLiteral("osd-shutd-laptop")},
0028         {SwitchToInternal, i18nd("kscreen_common", "Switch to laptop screen"), QStringLiteral("osd-shutd-screen")},
0029         {Clone, i18nd("kscreen_common", "Unify outputs"), QStringLiteral("osd-duplicate")},
0030         {ExtendLeft, i18nd("kscreen_common", "Extend to left"), QStringLiteral("osd-sbs-left")},
0031         {ExtendRight, i18nd("kscreen_common", "Extend to right"), QStringLiteral("osd-sbs-sright")},
0032         {NoAction, i18nd("kscreen_common", "Leave unchanged"), QStringLiteral("dialog-cancel")},
0033     };
0034 }
0035 
0036 void OsdAction::applyAction(const QSharedPointer<KScreen::Config> &config, Action action)
0037 {
0038     if (config->outputs().size() != 2) {
0039         return;
0040     }
0041     const auto copy = config->clone();
0042     const auto outputs = copy->outputs();
0043     auto internalIt = std::find_if(outputs.begin(), outputs.end(), [](const auto &output) {
0044         return output->type() == KScreen::Output::Type::Panel;
0045     });
0046     if (internalIt == outputs.end()) {
0047         internalIt = outputs.begin();
0048     }
0049     const auto internal = *internalIt;
0050     const auto external = *std::find_if(outputs.begin(), outputs.end(), [&internal](const auto &output) {
0051         return output != internal;
0052     });
0053     switch (action) {
0054     case KScreen::OsdAction::Action::NoAction:
0055         return;
0056     case KScreen::OsdAction::Action::SwitchToExternal:
0057         internal->setEnabled(false);
0058         external->setEnabled(true);
0059         external->setPos(QPoint());
0060         break;
0061     case KScreen::OsdAction::Action::SwitchToInternal:
0062         internal->setEnabled(true);
0063         internal->setPos(QPoint());
0064         external->setEnabled(false);
0065         break;
0066     case KScreen::OsdAction::Action::Clone: {
0067         internal->setEnabled(true);
0068         external->setEnabled(true);
0069         internal->setPos(QPoint());
0070         external->setPos(QPoint());
0071         QList<KScreen::ModePtr> commonModes;
0072         const auto internalModes = internal->modes();
0073         const auto externalModes = external->modes();
0074         for (const auto &mode : internalModes) {
0075             const bool shared = std::any_of(externalModes.begin(), externalModes.end(), [&mode](const auto &otherMode) {
0076                 return mode->size() == otherMode->size();
0077             });
0078             if (shared) {
0079                 commonModes.push_back(mode);
0080             }
0081         }
0082         if (commonModes.isEmpty()) {
0083             return;
0084         }
0085         std::sort(commonModes.begin(), commonModes.end(), [](const auto &left, const auto &right) {
0086             return left->size().width() < right->size().width() && left->size().height() < right->size().height();
0087         });
0088         const auto biggestSize = commonModes.back()->size();
0089         const auto findBestMode = [&biggestSize](const KScreen::OutputPtr &output) {
0090             auto list = output->modes();
0091             list.erase(std::remove_if(list.begin(),
0092                                       list.end(),
0093                                       [&biggestSize](const auto &mode) {
0094                                           return mode->size() != biggestSize;
0095                                       }),
0096                        list.end());
0097             return *std::max_element(list.begin(), list.end(), [](const auto &left, const auto &right) {
0098                 return left->refreshRate() < right->refreshRate();
0099             });
0100         };
0101         internal->setCurrentModeId(findBestMode(internal)->id());
0102         external->setCurrentModeId(findBestMode(external)->id());
0103         external->setScale(internal->scale());
0104         break;
0105     }
0106     case KScreen::OsdAction::Action::ExtendRight: {
0107         internal->setEnabled(true);
0108         external->setEnabled(true);
0109         internal->setPos(QPoint());
0110         const double internalScale = internal->scale();
0111         external->setPos(QPoint(std::ceil(internal->currentMode()->size().width() / internalScale), 0));
0112         break;
0113     }
0114     case KScreen::OsdAction::Action::ExtendLeft: {
0115         internal->setEnabled(true);
0116         external->setEnabled(true);
0117         external->setPos(QPoint());
0118         const double externalScale = external->scale();
0119         internal->setPos(QPoint(std::ceil(external->currentMode()->size().width() / externalScale), 0));
0120         break;
0121     }
0122     }
0123     new KScreen::SetConfigOperation(copy);
0124 }
0125 
0126 #include "moc_osdaction.cpp"