File indexing completed on 2024-11-10 04:57:04

0001 /*
0002     SPDX-FileCopyrightText: 2022 David Redondo <kde@david-redondo.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "outputlocator.h"
0008 #include "core/output.h"
0009 #include "effect/effecthandler.h"
0010 #include "effect/offscreenquickview.h"
0011 
0012 #include <algorithm>
0013 
0014 #include <KLocalizedString>
0015 
0016 #include <QDBusConnection>
0017 #include <QQuickItem>
0018 
0019 namespace KWin
0020 {
0021 
0022 static QString outputName(const Output *screen)
0023 {
0024     const auto screens = effects->screens();
0025     const bool shouldShowSerialNumber = std::any_of(screens.cbegin(), screens.cend(), [screen](const Output *other) {
0026         return other != screen && other->manufacturer() == screen->manufacturer() && other->model() == screen->model();
0027     });
0028     const bool shouldShowConnector = shouldShowSerialNumber && std::any_of(screens.cbegin(), screens.cend(), [screen](const Output *other) {
0029         return other != screen && other->serialNumber() == screen->serialNumber();
0030     });
0031 
0032     QStringList parts;
0033     if (!screen->manufacturer().isEmpty()) {
0034         parts.append(screen->manufacturer());
0035     }
0036 
0037     if (!screen->model().isEmpty()) {
0038         parts.append(screen->model());
0039     }
0040 
0041     if (shouldShowSerialNumber && !screen->serialNumber().isEmpty()) {
0042         parts.append(screen->serialNumber());
0043     }
0044 
0045     if (shouldShowConnector) {
0046         parts.append(screen->name());
0047     }
0048 
0049     if (parts.isEmpty()) {
0050         return i18nc("@label", "Unknown");
0051     } else {
0052         return parts.join(QLatin1Char(' '));
0053     }
0054 }
0055 
0056 OutputLocatorEffect::OutputLocatorEffect(QObject *parent)
0057     : Effect(parent)
0058     , m_qmlUrl(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kwin/effects/outputlocator/qml/OutputLabel.qml")))
0059 {
0060     QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/Effect/OutputLocator1"),
0061                                                  QStringLiteral("org.kde.KWin.Effect.OutputLocator1"),
0062                                                  this,
0063                                                  QDBusConnection::ExportAllSlots);
0064     connect(&m_showTimer, &QTimer::timeout, this, &OutputLocatorEffect::hide);
0065 }
0066 
0067 bool OutputLocatorEffect::isActive() const
0068 {
0069     return m_showTimer.isActive();
0070 }
0071 
0072 void OutputLocatorEffect::show()
0073 {
0074     if (isActive()) {
0075         m_showTimer.start(std::chrono::milliseconds(2500));
0076         return;
0077     }
0078 
0079     const auto screens = effects->screens();
0080     for (const auto screen : screens) {
0081         auto scene = new OffscreenQuickScene();
0082         scene->setSource(m_qmlUrl, {{QStringLiteral("outputName"), outputName(screen)}, {QStringLiteral("resolution"), screen->geometry().size()}, {QStringLiteral("scale"), screen->scale()}});
0083         QRectF geometry(0, 0, scene->rootItem()->implicitWidth(), scene->rootItem()->implicitHeight());
0084         geometry.moveCenter(screen->geometry().center());
0085         scene->setGeometry(geometry.toRect());
0086         connect(scene, &OffscreenQuickView::repaintNeeded, this, [scene] {
0087             effects->addRepaint(scene->geometry());
0088         });
0089         m_scenesByScreens[screen].reset(scene);
0090     }
0091 
0092     m_showTimer.start(std::chrono::milliseconds(2500));
0093 }
0094 
0095 void OutputLocatorEffect::hide()
0096 {
0097     m_showTimer.stop();
0098 
0099     QRegion repaintRegion;
0100     for (const auto &[screen, scene] : m_scenesByScreens) {
0101         repaintRegion += scene->geometry();
0102     }
0103 
0104     m_scenesByScreens.clear();
0105     effects->addRepaint(repaintRegion);
0106 }
0107 
0108 void OutputLocatorEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, KWin::Output *screen)
0109 {
0110     effects->paintScreen(renderTarget, viewport, mask, region, screen);
0111     // On X11 all screens are painted at once
0112     if (effects->waylandDisplay()) {
0113         if (auto it = m_scenesByScreens.find(screen); it != m_scenesByScreens.end()) {
0114             effects->renderOffscreenQuickView(renderTarget, viewport, it->second.get());
0115         }
0116     } else {
0117         for (const auto &[screen, scene] : m_scenesByScreens) {
0118             effects->renderOffscreenQuickView(renderTarget, viewport, scene.get());
0119         }
0120     }
0121 }
0122 }
0123 
0124 #include "moc_outputlocator.cpp"