1 /*
2     SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 #include "output_identifier.h"
7 
8 #include "../common/utils.h"
9 
10 #include <kscreen/output.h>
11 
12 #include <QQuickItem>
13 #include <QStandardPaths>
14 #include <QTimer>
15 
16 #include <KDeclarative/kdeclarative/qmlobject.h>
17 #include <PlasmaQuick/Dialog>
18 
19 #define QML_PATH "kpackage/kcms/kcm_kscreen/contents/ui/"
20 
OutputIdentifier(KScreen::ConfigPtr config,QObject * parent)21 OutputIdentifier::OutputIdentifier(KScreen::ConfigPtr config, QObject *parent)
22     : QObject(parent)
23 {
24     const QString qmlPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(QML_PATH "OutputIdentifier.qml"));
25 
26     for (const auto &output : config->connectedOutputs()) {
27         if (!output->currentMode()) {
28             continue;
29         }
30 
31         const KScreen::ModePtr mode = output->currentMode();
32         auto *view = new PlasmaQuick::Dialog();
33 
34         auto qmlObject = new KDeclarative::QmlObject(view);
35         qmlObject->setSource(QUrl::fromLocalFile(qmlPath));
36         qmlObject->completeInitialization();
37 
38         auto rootObj = qobject_cast<QQuickItem *>(qmlObject->rootObject());
39 
40         view->setMainItem(rootObj);
41         view->setFlags(Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint);
42         view->setBackgroundHints(PlasmaQuick::Dialog::NoBackground);
43         view->installEventFilter(this);
44 
45         if (!rootObj) {
46             delete view;
47             continue;
48         }
49 
50         QSize deviceSize, logicalSize;
51         if (output->isHorizontal()) {
52             deviceSize = mode->size();
53         } else {
54             deviceSize = QSize(mode->size().height(), mode->size().width());
55         }
56         if (config->supportedFeatures() & KScreen::Config::Feature::PerOutputScaling) {
57             // Scale adjustment is not needed on Wayland, we use logical size.
58             logicalSize = output->logicalSize().toSize();
59         } else {
60             logicalSize = deviceSize / view->effectiveDevicePixelRatio();
61         }
62         rootObj->setProperty("outputName", Utils::outputName(output));
63         rootObj->setProperty("modeName", Utils::sizeToString(deviceSize));
64         view->setProperty("screenSize", QRect(output->pos(), logicalSize));
65         m_views << view;
66     }
67 
68     for (auto *view : m_views) {
69         view->show();
70     }
71     QTimer::singleShot(2500, this, &OutputIdentifier::identifiersFinished);
72 }
73 
~OutputIdentifier()74 OutputIdentifier::~OutputIdentifier()
75 {
76     qDeleteAll(m_views);
77 }
78 
eventFilter(QObject * object,QEvent * event)79 bool OutputIdentifier::eventFilter(QObject *object, QEvent *event)
80 {
81     if (event->type() == QEvent::Resize) {
82         if (m_views.contains(qobject_cast<PlasmaQuick::Dialog *>(object))) {
83             QResizeEvent *e = static_cast<QResizeEvent *>(event);
84             const QRect screenSize = object->property("screenSize").toRect();
85             QRect geometry(QPoint(0, 0), e->size());
86             geometry.moveCenter(screenSize.center());
87             static_cast<PlasmaQuick::Dialog *>(object)->setGeometry(geometry);
88         }
89     }
90     return QObject::eventFilter(object, event);
91 }
92