1 /*
2  *  SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
3  *
4  *  SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 
7 #include "settings.h"
8 
9 #include <QDebug>
10 #include <QFile>
11 #include <QGuiApplication>
12 #include <QIcon>
13 #include <QMouseEvent>
14 #include <QSettings>
15 #include <QStandardPaths>
16 #include <QTouchDevice>
17 #include <QWindow>
18 
19 #include <QtGui/private/qguiapplication_p.h>
20 #include <QtGui/qpa/qplatformmenu.h>
21 #include <QtGui/qpa/qplatformtheme.h>
22 
23 #include "libkirigami/tabletmodewatcher.h"
24 
25 #ifndef KIRIGAMI_BUILD_TYPE_STATIC
26 #include "../kirigami_version.h"
27 #endif
28 
29 class SettingsSingleton
30 {
31 public:
32     Settings self;
33 };
34 
Q_GLOBAL_STATIC(SettingsSingleton,privateSettingsSelf)35 Q_GLOBAL_STATIC(SettingsSingleton, privateSettingsSelf)
36 
37 Settings::Settings(QObject *parent)
38     : QObject(parent)
39     , m_hasTouchScreen(false)
40     , m_hasTransientTouchInput(false)
41 {
42     m_tabletModeAvailable = Kirigami::TabletModeWatcher::self()->isTabletModeAvailable();
43     connect(Kirigami::TabletModeWatcher::self(), &Kirigami::TabletModeWatcher::tabletModeAvailableChanged, this, [this](bool tabletModeAvailable) {
44         setTabletModeAvailable(tabletModeAvailable);
45     });
46 
47     m_tabletMode = Kirigami::TabletModeWatcher::self()->isTabletMode();
48     connect(Kirigami::TabletModeWatcher::self(), &Kirigami::TabletModeWatcher::tabletModeChanged, this, [this](bool tabletMode) {
49         setTabletMode(tabletMode);
50     });
51 
52 #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(UBUNTU_TOUCH)
53     m_mobile = true;
54     m_hasTouchScreen = true;
55 #else
56     // Mostly for debug purposes and for platforms which are always mobile,
57     // such as Plasma Mobile
58     if (qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_MOBILE")) {
59         m_mobile = QByteArrayList{"1", "true"}.contains(qgetenv("QT_QUICK_CONTROLS_MOBILE"));
60     } else {
61         m_mobile = false;
62     }
63 
64     const auto touchDevices = QTouchDevice::devices();
65     for (const auto &device : touchDevices) {
66         if (device->type() == QTouchDevice::TouchScreen) {
67             m_hasTouchScreen = true;
68             break;
69         }
70     }
71     if (m_hasTouchScreen) {
72         connect(qApp, &QGuiApplication::focusWindowChanged, this, [this](QWindow *win) {
73             if (win) {
74                 win->installEventFilter(this);
75             }
76         });
77     }
78 #endif
79 
80     auto bar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
81     m_hasPlatformMenuBar = bar != nullptr;
82     if (bar != nullptr) {
83         bar->deleteLater();
84     }
85 
86     const QString configPath = QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("kdeglobals"));
87     if (QFile::exists(configPath)) {
88         QSettings globals(configPath, QSettings::IniFormat);
89         globals.beginGroup(QStringLiteral("KDE"));
90         m_scrollLines = qMax(1, globals.value(QStringLiteral("WheelScrollLines"), 3).toInt());
91     } else {
92         m_scrollLines = 3;
93     }
94 }
95 
~Settings()96 Settings::~Settings()
97 {
98 }
99 
self()100 Settings *Settings::self()
101 {
102     return &privateSettingsSelf()->self;
103 }
104 
eventFilter(QObject * watched,QEvent * event)105 bool Settings::eventFilter(QObject *watched, QEvent *event)
106 {
107     Q_UNUSED(watched)
108     switch (event->type()) {
109     case QEvent::TouchBegin:
110         setTransientTouchInput(true);
111         break;
112     case QEvent::MouseButtonPress:
113     case QEvent::MouseMove: {
114         QMouseEvent *me = static_cast<QMouseEvent *>(event);
115         if (me->source() == Qt::MouseEventNotSynthesized) {
116             setTransientTouchInput(false);
117         }
118         break;
119     }
120     case QEvent::Wheel:
121         setTransientTouchInput(false);
122     default:
123         break;
124     }
125 
126     return false;
127 }
128 
setTabletModeAvailable(bool mobileAvailable)129 void Settings::setTabletModeAvailable(bool mobileAvailable)
130 {
131     if (mobileAvailable == m_tabletModeAvailable) {
132         return;
133     }
134 
135     m_tabletModeAvailable = mobileAvailable;
136     Q_EMIT tabletModeAvailableChanged();
137 }
138 
isTabletModeAvailable() const139 bool Settings::isTabletModeAvailable() const
140 {
141     return m_tabletModeAvailable;
142 }
143 
setIsMobile(bool mobile)144 void Settings::setIsMobile(bool mobile)
145 {
146     if (mobile == m_mobile) {
147         return;
148     }
149 
150     m_mobile = mobile;
151     Q_EMIT isMobileChanged();
152 }
153 
isMobile() const154 bool Settings::isMobile() const
155 {
156     return m_mobile;
157 }
158 
setTabletMode(bool tablet)159 void Settings::setTabletMode(bool tablet)
160 {
161     if (tablet == m_tabletMode) {
162         return;
163     }
164 
165     m_tabletMode = tablet;
166     Q_EMIT tabletModeChanged();
167 }
168 
tabletMode() const169 bool Settings::tabletMode() const
170 {
171     return m_tabletMode;
172 }
173 
setTransientTouchInput(bool touch)174 void Settings::setTransientTouchInput(bool touch)
175 {
176     if (touch == m_hasTransientTouchInput) {
177         return;
178     }
179 
180     m_hasTransientTouchInput = touch;
181     if (!m_tabletMode) {
182         Q_EMIT hasTransientTouchInputChanged();
183     }
184 }
185 
hasTransientTouchInput() const186 bool Settings::hasTransientTouchInput() const
187 {
188     return m_hasTransientTouchInput || m_tabletMode;
189 }
190 
style() const191 QString Settings::style() const
192 {
193     return m_style;
194 }
195 
setStyle(const QString & style)196 void Settings::setStyle(const QString &style)
197 {
198     m_style = style;
199 }
200 
mouseWheelScrollLines() const201 int Settings::mouseWheelScrollLines() const
202 {
203     return m_scrollLines;
204 }
205 
information() const206 QStringList Settings::information() const
207 {
208     return {
209 #ifndef KIRIGAMI_BUILD_TYPE_STATIC
210         tr("KDE Frameworks %1").arg(QStringLiteral(KIRIGAMI2_VERSION_STRING)),
211 #endif
212         tr("The %1 windowing system").arg(QGuiApplication::platformName()),
213         tr("Qt %2 (built against %3)").arg(QString::fromLocal8Bit(qVersion()), QStringLiteral(QT_VERSION_STR))};
214 }
215 
applicationWindowIcon() const216 QVariant Settings::applicationWindowIcon() const
217 {
218     const QIcon &windowIcon = qApp->windowIcon();
219     if (windowIcon.isNull()) {
220         return QVariant();
221     }
222     return windowIcon;
223 }
224 
hasPlatformMenuBar() const225 bool Settings::hasPlatformMenuBar() const
226 {
227     return m_hasPlatformMenuBar;
228 }
229