1 /********************************************************************
2 Copyright © 2019 Roman Gilg <subdiff@gmail.com>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 *********************************************************************/
17 #include "output_identifier.h"
18 
19 #include "../common/utils.h"
20 
21 #include <disman/output.h>
22 
23 #include <QQuickItem>
24 #include <QQuickView>
25 #include <QStandardPaths>
26 #include <QSurfaceFormat>
27 #include <QTimer>
28 
29 #define QML_PATH "kpackage/kcms/kcm_kdisplay/contents/ui/"
30 
OutputIdentifier(Disman::ConfigPtr config,QObject * parent)31 OutputIdentifier::OutputIdentifier(Disman::ConfigPtr config, QObject* parent)
32     : QObject(parent)
33 {
34     QQuickWindow::setDefaultAlphaBuffer(true);
35     const QString qmlPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
36                                                    QStringLiteral(QML_PATH "OutputIdentifier.qml"));
37 
38     for (auto const& [key, output] : config->outputs()) {
39         if (!output->auto_mode()) {
40             continue;
41         }
42 
43         auto const mode = output->auto_mode();
44 
45         auto view = new QQuickView;
46         QSurfaceFormat format;
47         format.setAlphaBufferSize(8);
48         view->setFormat(format);
49         view->setColor(QColor(0, 0, 0, 0));
50         view->setFlags(Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint);
51         view->setSource(QUrl::fromLocalFile(qmlPath));
52 
53         view->installEventFilter(this);
54 
55         auto rootObj = view->rootObject();
56         if (!rootObj) {
57             delete view;
58             continue;
59         }
60 
61         QSize deviceSize;
62         QSizeF logicalSize;
63         if (output->horizontal()) {
64             deviceSize = mode->size();
65         } else {
66             deviceSize = QSize(mode->size().height(), mode->size().width());
67         }
68         if (config->supported_features() & Disman::Config::Feature::PerOutputScaling) {
69             // Scale adjustment is not needed on Wayland, we use logical size.
70             logicalSize = output->geometry().size();
71         } else {
72             logicalSize = deviceSize / view->effectiveDevicePixelRatio();
73         }
74         rootObj->setProperty("outputName", Utils::outputName(output));
75         rootObj->setProperty("modeName", Utils::sizeToString(deviceSize));
76         view->setProperty("screenSize", QRectF(output->position(), logicalSize).toRect());
77         m_views << view;
78     }
79 
80     for (auto* view : m_views) {
81         view->show();
82     }
83     QTimer::singleShot(2500, this, &OutputIdentifier::identifiersFinished);
84 }
85 
~OutputIdentifier()86 OutputIdentifier::~OutputIdentifier()
87 {
88     qDeleteAll(m_views);
89 }
90 
eventFilter(QObject * object,QEvent * event)91 bool OutputIdentifier::eventFilter(QObject* object, QEvent* event)
92 {
93     if (event->type() == QEvent::Resize) {
94         if (m_views.contains(qobject_cast<QQuickView*>(object))) {
95             QResizeEvent* e = static_cast<QResizeEvent*>(event);
96             const QRect screenSize = object->property("screenSize").toRect();
97             QRect geometry(QPoint(0, 0), e->size());
98             geometry.moveCenter(screenSize.center());
99             static_cast<QQuickView*>(object)->setGeometry(geometry);
100         }
101     }
102     return QObject::eventFilter(object, event);
103 }
104