File: osdaction.cpp

package info (click to toggle)
kscreen 4%3A6.5.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,444 kB
  • sloc: cpp: 6,786; xml: 19; makefile: 7; sh: 5
file content (177 lines) | stat: -rw-r--r-- 7,879 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
    SPDX-FileCopyrightText: 2016 Sebastian Kügler <sebas@kde.org>

    Work sponsored by the LiMux project of the city of Munich:
    SPDX-FileCopyrightText: 2018 Kai Uwe Broulik <kde@broulik.de>

    SPDX-FileCopyrightText: 2022 David Redondo <kde@david-redondo.de>
    SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "osdaction.h"
#include "output.h"

#include <KLocalizedString>
#include <KScreen/Config>
#include <KScreen/Mode>
#include <KScreen/Output>
#include <KScreen/SetConfigOperation>
#include <QPoint>

using namespace KScreen;

QList<OsdAction> OsdAction::availableActions()
{
    return {
        {SwitchToExternal, i18nd("kscreen_common", "Only use external screen"), QStringLiteral("osd-shutd-laptop")},
        {SwitchToInternal, i18nd("kscreen_common", "Only use built-in screen"), QStringLiteral("osd-shutd-screen")},
        {Clone, i18nd("kscreen_common", "Mirror screens"), QStringLiteral("osd-duplicate")},
        {ExtendLeft, i18nd("kscreen_common", "Extend to left of built-in screen"), QStringLiteral("osd-sbs-left")},
        {ExtendRight, i18nd("kscreen_common", "Extend to right of built-in screen"), QStringLiteral("osd-sbs-sright")},
        {NoAction, i18nd("kscreen_common", "Leave unchanged"), QStringLiteral("dialog-cancel")},
    };
}

KScreen::SetConfigOperation *OsdAction::applyAction(const QSharedPointer<KScreen::Config> &config, Action action)
{
    const ConfigPtr copy = config->clone();
    const OutputList outputs = copy->connectedOutputs();
    if (outputs.size() != 2) {
        return nullptr;
    }

    auto internalIt = std::find_if(outputs.cbegin(), outputs.cend(), [](const auto &output) {
        return output->type() == KScreen::Output::Type::Panel;
    });
    if (internalIt == outputs.end()) {
        internalIt = outputs.begin();
    }
    const OutputPtr &internal = *internalIt;
    const OutputPtr &external = *std::find_if(outputs.cbegin(), outputs.cend(), [&internal](const auto &output) {
        return output != internal;
    });

    if (config->supportedFeatures() & Config::Feature::PerOutputScaling) {
        external->setReplicationSource(0);
        internal->setReplicationSource(0);
    } else {
        if (!internal->isEnabled()) {
            internal->setRotation(::Output::readGlobal(internal).rotation.value_or(Output::Rotation::None));
        }
        if (!external->isEnabled()) {
            external->setRotation(::Output::readGlobal(external).rotation.value_or(Output::Rotation::None));
        }
    }

    switch (action) {
    case KScreen::OsdAction::Action::NoAction:
        return nullptr;
    case KScreen::OsdAction::Action::SwitchToExternal:
        internal->setEnabled(false);
        external->setEnabled(true);
        external->setPos(QPoint());
        break;
    case KScreen::OsdAction::Action::SwitchToInternal:
        internal->setEnabled(true);
        internal->setPos(QPoint());
        external->setEnabled(false);
        break;
    case KScreen::OsdAction::Action::Clone: {
        internal->setEnabled(true);
        external->setEnabled(true);
        if (config->supportedFeatures() & Config::Feature::PerOutputScaling) {
            // on Wayland, KWin deals with modes, we just set the replication source
            external->setReplicationSource(internal->id());
            internal->setReplicationSource(0);
        } else {
            // keep the old code path for Xorg
            internal->setEnabled(true);
            external->setEnabled(true);
            internal->setPos(QPoint());
            external->setPos(QPoint());
            QList<KScreen::ModePtr> commonModes;
            const auto internalModes = internal->modes();
            const auto externalModes = external->modes();
            for (const auto &mode : internalModes) {
                const bool shared = std::any_of(externalModes.begin(), externalModes.end(), [&mode](const auto &otherMode) {
                    return mode->size() == otherMode->size();
                });
                if (shared) {
                    commonModes.push_back(mode);
                }
            }
            if (commonModes.isEmpty()) {
                return nullptr;
            }
            const auto biggestSizeIt = std::max_element(commonModes.begin(), commonModes.end(), [](const auto &left, const auto &right) {
                if (left->size().width() != right->size().width()) {
                    return left->size().width() < right->size().width();
                }
                return left->size().height() < right->size().height();
            });
            const auto biggestSize = (*biggestSizeIt)->size();
            const auto findBestMode = [&biggestSize](const KScreen::OutputPtr &output) {
                auto list = output->modes();
                list.erase(std::remove_if(list.begin(),
                                          list.end(),
                                          [&biggestSize](const auto &mode) {
                                              return mode->size() != biggestSize;
                                          }),
                           list.end());
                return *std::max_element(list.begin(), list.end(), [](const auto &left, const auto &right) {
                    return left->refreshRate() < right->refreshRate();
                });
            };
            internal->setCurrentModeId(findBestMode(internal)->id());
            external->setCurrentModeId(findBestMode(external)->id());
            external->setScale(internal->scale());
        }
        break;
    }
    case KScreen::OsdAction::Action::ExtendRight: {
        internal->setEnabled(true);
        external->setEnabled(true);
        internal->setPos(QPoint());
        ModePtr currentMode = internal->currentMode();
        if (!currentMode) { // When the internal display is not enabled
            const auto internalModesMap = internal->modes();
            Q_ASSERT(!internalModesMap.empty());
            auto bestModeIt = std::max_element(internalModesMap.cbegin(), internalModesMap.cend(), [](const auto &left, const auto &right) {
                const QSize leftSize = left->size();
                const QSize rightSize = right->size();
                return (leftSize.width() < rightSize.width() && leftSize.height() < rightSize.height())
                    || (leftSize == rightSize && left->refreshRate() < right->refreshRate());
            });
            currentMode = bestModeIt.value();
            internal->setCurrentModeId(currentMode->id());
        }
        external->setPos({copy->logicalSizeForOutputInt(*internal).width(), 0});
        break;
    }
    case KScreen::OsdAction::Action::ExtendLeft: {
        internal->setEnabled(true);
        external->setEnabled(true);
        external->setPos(QPoint());
        ModePtr currentMode = external->currentMode();
        if (!currentMode) { // When the external display is not enabled
            const auto externalModesMap = external->modes();
            Q_ASSERT(!externalModesMap.empty());
            auto bestModeIt = std::max_element(externalModesMap.cbegin(), externalModesMap.cend(), [](const auto &left, const auto &right) {
                const QSize leftSize = left->size();
                const QSize rightSize = right->size();
                return (leftSize.width() < rightSize.width() && leftSize.height() < rightSize.height())
                    || (leftSize == rightSize && left->refreshRate() < right->refreshRate());
            });
            currentMode = bestModeIt.value();
            external->setCurrentModeId(currentMode->id());
        }
        internal->setPos({copy->logicalSizeForOutputInt(*external).width(), 0});
        break;
    }
    }
    return new KScreen::SetConfigOperation(copy);
}

#include "moc_osdaction.cpp"