1 /*
2     Copyright (C) 2016-2018 Chih-Hsuan Yen <yan12125@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 along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include "touchpadconfig.h"
20 #include "touchpaddevice.h"
21 
22 #include <cmath>
23 #include <QUrl>
24 #include <LXQt/AutostartEntry>
25 #include <LXQt/Settings>
26 
TouchpadConfig(LXQt::Settings * _settings,QWidget * parent)27 TouchpadConfig::TouchpadConfig(LXQt::Settings* _settings, QWidget* parent):
28     QWidget(parent),
29     settings(_settings)
30 {
31     ui.setupUi(this);
32 
33     devices = TouchpadDevice::enumerate_from_udev();
34     for (const TouchpadDevice& device : qAsConst(devices))
35     {
36         ui.devicesComboBox->addItem(device.name());
37     }
38 
39     initControls();
40 
41     connect(ui.devicesComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
42             this, [this] (int/* index*/) { initControls(); }); // update GUI on device change
43     connect(ui.tappingEnabledCheckBox, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
44     connect(ui.naturalScrollingEnabledCheckBox, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
45     connect(ui.tapToDragEnabledCheckBox, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
46     connect(ui.accelSpeedDoubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &TouchpadConfig::settingsChanged);
47     connect(ui.noScrollingRadioButton, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
48     connect(ui.twoFingerScrollingRadioButton, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
49     connect(ui.edgeScrollingRadioButton, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
50     connect(ui.buttonScrollingRadioButton, &QAbstractButton::clicked, this, &TouchpadConfig::settingsChanged);
51 }
52 
~TouchpadConfig()53 TouchpadConfig::~TouchpadConfig()
54 {
55 }
56 
initFeatureControl(QCheckBox * control,int featureEnabled)57 void TouchpadConfig::initFeatureControl(QCheckBox* control, int featureEnabled)
58 {
59     if (featureEnabled >= 0)
60     {
61         control->setEnabled(true);
62         control->setCheckState(featureEnabled ? Qt::Checked : Qt::Unchecked);
63     }
64     else
65     {
66         control->setEnabled(false);
67     }
68 }
69 
initControls()70 void TouchpadConfig::initControls()
71 {
72     int curDevice = ui.devicesComboBox->currentIndex();
73     if (curDevice < 0) {
74         return;
75     }
76 
77     const TouchpadDevice& device = devices[curDevice];
78     initFeatureControl(ui.tappingEnabledCheckBox, device.tappingEnabled());
79     initFeatureControl(ui.naturalScrollingEnabledCheckBox, device.naturalScrollingEnabled());
80     initFeatureControl(ui.tapToDragEnabledCheckBox, device.tapToDragEnabled());
81 
82     auto ok = device.xinputDriverSupported();
83     if (!ok) {
84       ui.deviceInfoLabel->setText(
85             tr(
86               "LXQt only supports \"libinput\" as xinput driver.\n"
87               "(current value: %1)\n"
88               "\n"
89               "If this is intended, please configure xinput manually.\n"
90               "Otherwise you can get rid of this message by changing xinput driver to \"libinput\".\n")
91             .arg(device.xinputDriver()));
92       ui.deviceInfoLabel->setStyleSheet(QStringLiteral("background-color: #f88; border-color: #f33; border-size: 1px"));
93     };
94     ui.deviceInfoLabel->setVisible(!ok);
95     ui.deviceInfoLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
96 
97     float accelSpeed = device.accelSpeed();
98     if (!std::isnan(accelSpeed)) {
99         ui.accelSpeedDoubleSpinBox->setEnabled(true);
100         // prevent setAccelSpeed() from being called because the device may have changed
101         ui.accelSpeedDoubleSpinBox->blockSignals(true);
102         ui.accelSpeedDoubleSpinBox->setValue(accelSpeed);
103         ui.accelSpeedDoubleSpinBox->blockSignals(false);
104     } else {
105         ui.accelSpeedDoubleSpinBox->setEnabled(false);
106     }
107 
108     int scrollMethodsAvailable = device.scrollMethodsAvailable();
109     ui.twoFingerScrollingRadioButton->setEnabled(scrollMethodsAvailable & TWO_FINGER);
110     ui.edgeScrollingRadioButton->setEnabled(scrollMethodsAvailable & EDGE);
111     ui.buttonScrollingRadioButton->setEnabled(scrollMethodsAvailable & BUTTON);
112 
113     ScrollingMethod scrollingMethodEnabled = device.scrollingMethodEnabled();
114     if (scrollingMethodEnabled == TWO_FINGER)
115     {
116         ui.twoFingerScrollingRadioButton->setChecked(true);
117     }
118     else if (scrollingMethodEnabled == EDGE)
119     {
120         ui.edgeScrollingRadioButton->setChecked(true);
121     }
122     else if (scrollingMethodEnabled == BUTTON)
123     {
124         ui.buttonScrollingRadioButton->setChecked(true);
125     }
126     else
127     {
128         ui.noScrollingRadioButton->setChecked(true);
129     }
130 }
131 
accept()132 void TouchpadConfig::accept()
133 {
134     for (const TouchpadDevice& device : qAsConst(devices))
135     {
136         device.saveSettings(settings);
137     }
138 
139     LXQt::AutostartEntry autoStart(QStringLiteral("lxqt-config-touchpad-autostart.desktop"));
140     XdgDesktopFile desktopFile(XdgDesktopFile::ApplicationType, QStringLiteral("lxqt-config-touchpad-autostart"), QStringLiteral("lxqt-config-input --load-touchpad"));
141     desktopFile.setValue(QStringLiteral("OnlyShowIn"), QStringLiteral("LXQt"));
142     desktopFile.setValue(QStringLiteral("Comment"), QStringLiteral("Autostart touchpad settings for lxqt-config-input"));
143     autoStart.setFile(desktopFile);
144     autoStart.commit();
145 }
146 
reset()147 void TouchpadConfig::reset()
148 {
149     for (const TouchpadDevice& device : qAsConst(devices))
150     {
151         device.setTappingEnabled(device.oldTappingEnabled());
152         device.setNaturalScrollingEnabled(device.oldNaturalScrollingEnabled());
153         device.setTapToDragEnabled(device.oldTapToDragEnabled());
154         device.setAccelSpeed(device.oldAccelSpeed());
155         device.setScrollingMethodEnabled(device.oldScrollingMethodEnabled());
156     }
157     initControls();
158     accept();
159 }
160 
applyConfig()161 void TouchpadConfig::applyConfig()
162 {
163     int curDevice = ui.devicesComboBox->currentIndex();
164     if (curDevice < 0) {
165         return;
166     }
167 
168     bool acceptSetting = false;
169     TouchpadDevice& device = devices[curDevice];
170 
171     bool enable = ui.tappingEnabledCheckBox->checkState() == Qt::Checked;
172     if (enable != (device.tappingEnabled() > 0))
173     {
174         device.setTappingEnabled(enable);
175         acceptSetting = true;
176     }
177 
178     enable = ui.naturalScrollingEnabledCheckBox->checkState() == Qt::Checked;
179     if (enable != (device.naturalScrollingEnabled() > 0))
180     {
181         device.setNaturalScrollingEnabled(enable);
182         acceptSetting = true;
183     }
184 
185     enable = ui.tapToDragEnabledCheckBox->checkState() == Qt::Checked;
186     if (enable != (device.tapToDragEnabled() > 0))
187     {
188         device.setTapToDragEnabled(enable);
189         acceptSetting = true;
190     }
191 
192     float accelSpeed = static_cast<float>(ui.accelSpeedDoubleSpinBox->value());
193     if (accelSpeed != device.accelSpeed())
194     {
195         device.setAccelSpeed(accelSpeed);
196         acceptSetting = true;
197     }
198 
199     // these radio buttons are auto-exclusive
200     ScrollingMethod m = NONE;
201     if (ui.noScrollingRadioButton->isChecked())
202         m = NONE;
203     else if (ui.twoFingerScrollingRadioButton->isChecked())
204         m = TWO_FINGER;
205     else if (ui.edgeScrollingRadioButton->isChecked())
206         m = EDGE;
207     else if (ui.buttonScrollingRadioButton->isChecked())
208         m = BUTTON;
209     if (m != device.scrollingMethodEnabled())
210     {
211         device.setScrollingMethodEnabled(m);
212         acceptSetting = true;
213     }
214 
215     if (acceptSetting)
216         accept();
217 }
218