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