Changeset View
Changeset View
Standalone View
Standalone View
kcms/touchpadx/src/backends/x11/xlibtouchpad.cpp
- This file was added.
1 | #include <cmath> | ||||
---|---|---|---|---|---|
2 | | ||||
3 | #include "xlibtouchpad.h" | ||||
4 | #include <X11/Xlib-xcb.h> | ||||
5 | #include <X11/extensions/XInput.h> | ||||
6 | #include <X11/extensions/XInput2.h> | ||||
7 | #include <xserver-properties.h> | ||||
8 | | ||||
9 | static QVariant negateVariant(const QVariant &value) | ||||
10 | { | ||||
11 | if (value.type() == QVariant::Double) { | ||||
12 | return QVariant(-value.toDouble()); | ||||
13 | } else if (value.type() == QVariant::Int) { | ||||
14 | return QVariant(-value.toInt()); | ||||
15 | } | ||||
16 | return value; | ||||
17 | } | ||||
18 | | ||||
19 | XlibTouchpad::XlibTouchpad(Display *display, int deviceId) : | ||||
20 | m_display(display), | ||||
21 | m_connection(XGetXCBConnection(display)), | ||||
22 | m_deviceId(deviceId) | ||||
23 | { | ||||
24 | m_floatType.intern(m_connection, "FLOAT"); | ||||
25 | m_enabledAtom.intern(m_connection, XI_PROP_ENABLED); | ||||
26 | } | ||||
27 | | ||||
28 | bool XlibTouchpad::applyConfig(const QVariantHash& p) | ||||
29 | { | ||||
30 | m_props.clear(); | ||||
31 | | ||||
32 | bool error = false; | ||||
33 | Q_FOREACH(const QString &name, m_supported) { | ||||
34 | QVariantHash::ConstIterator i = p.find(name); | ||||
35 | if (i == p.end()) { | ||||
36 | continue; | ||||
37 | } | ||||
38 | const Parameter *par = findParameter(name); | ||||
39 | if (par) { | ||||
40 | QVariant value(i.value()); | ||||
41 | | ||||
42 | double k = getPropertyScale(name); | ||||
43 | if (k != 1.0) { | ||||
44 | bool ok = false; | ||||
45 | value = QVariant(value.toDouble(&ok) * k); | ||||
46 | if (!ok) { | ||||
47 | error = true; | ||||
48 | continue; | ||||
49 | } | ||||
50 | } | ||||
51 | | ||||
52 | if (m_negate.contains(name)) { | ||||
53 | QVariantHash::ConstIterator i = p.find(m_negate[name]); | ||||
54 | if (i != p.end() && i.value().toBool()) { | ||||
55 | value = negateVariant(value); | ||||
56 | } | ||||
57 | } | ||||
58 | | ||||
59 | if (name == "CoastingSpeed") { | ||||
60 | QVariantHash::ConstIterator coastingEnabled = p.find("Coasting"); | ||||
61 | if (coastingEnabled != p.end() && | ||||
62 | !coastingEnabled.value().toBool()) | ||||
63 | { | ||||
64 | value = QVariant(0); | ||||
65 | } | ||||
66 | } | ||||
67 | | ||||
68 | if (!setParameter(par, value)) { | ||||
69 | error = true; | ||||
70 | } | ||||
71 | } | ||||
72 | } | ||||
73 | | ||||
74 | flush(); | ||||
75 | | ||||
76 | return !error; | ||||
77 | } | ||||
78 | | ||||
79 | bool XlibTouchpad::getConfig(QVariantHash& p) | ||||
80 | { | ||||
81 | if (m_supported.isEmpty()) { | ||||
82 | return false; | ||||
83 | } | ||||
84 | | ||||
85 | m_props.clear(); | ||||
86 | | ||||
87 | bool error = false; | ||||
88 | Q_FOREACH(const QString &name, m_supported) { | ||||
89 | const Parameter *par = findParameter(name); | ||||
90 | if (!par) { | ||||
91 | continue; | ||||
92 | } | ||||
93 | | ||||
94 | QVariant value(getParameter(par)); | ||||
95 | if (!value.isValid()) { | ||||
96 | error = true; | ||||
97 | continue; | ||||
98 | } | ||||
99 | | ||||
100 | double k = getPropertyScale(name); | ||||
101 | if (k != 1.0) { | ||||
102 | bool ok = false; | ||||
103 | value = QVariant(value.toDouble(&ok) / k); | ||||
104 | if (!ok) { | ||||
105 | error = true; | ||||
106 | continue; | ||||
107 | } | ||||
108 | } | ||||
109 | | ||||
110 | if (m_negate.contains(name)) { | ||||
111 | bool negative = value.toDouble() < 0.0; | ||||
112 | p[m_negate[name]] = QVariant(negative); | ||||
113 | if (negative) { | ||||
114 | value = negateVariant(value); | ||||
115 | } | ||||
116 | } | ||||
117 | | ||||
118 | if (name == "CoastingSpeed") { | ||||
119 | bool coasting = value.toDouble() != 0.0; | ||||
120 | p["Coasting"] = QVariant(coasting); | ||||
121 | if (!coasting) { | ||||
122 | continue; | ||||
123 | } | ||||
124 | } | ||||
125 | | ||||
126 | p[name] = value; | ||||
127 | } | ||||
128 | | ||||
129 | return !error; | ||||
130 | } | ||||
131 | | ||||
132 | void XlibTouchpad::loadSupportedProperties(const Parameter* props) | ||||
133 | { | ||||
134 | m_paramList = props; | ||||
135 | for (const Parameter *param = props; param->name; param++) { | ||||
136 | QLatin1String name(param->prop_name); | ||||
137 | | ||||
138 | if (!m_atoms.contains(name)) { | ||||
139 | m_atoms.insert(name, QSharedPointer<XcbAtom>( | ||||
140 | new XcbAtom(m_connection, param->prop_name))); | ||||
141 | } | ||||
142 | } | ||||
143 | | ||||
144 | for (const Parameter *p = props; p->name; p++) { | ||||
145 | if (getParameter(p).isValid()) { | ||||
146 | m_supported.append(p->name); | ||||
147 | } | ||||
148 | } | ||||
149 | } | ||||
150 | | ||||
151 | QVariant XlibTouchpad::getParameter(const Parameter* par) | ||||
152 | { | ||||
153 | PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name)); | ||||
154 | if (!p || par->prop_offset >= p->nitems) { | ||||
155 | return QVariant(); | ||||
156 | } | ||||
157 | | ||||
158 | return p->value(par->prop_offset); | ||||
159 | } | ||||
160 | | ||||
161 | | ||||
162 | void XlibTouchpad::flush() | ||||
163 | { | ||||
164 | Q_FOREACH(const QLatin1String &name, m_changed) { | ||||
165 | m_props[name].set(); | ||||
166 | } | ||||
167 | m_changed.clear(); | ||||
168 | | ||||
169 | XFlush(m_display); | ||||
170 | } | ||||
171 | | ||||
172 | double XlibTouchpad::getPropertyScale(const QString& name) const | ||||
173 | { | ||||
174 | Q_UNUSED(name); | ||||
175 | return 1.0; | ||||
176 | } | ||||
177 | | ||||
178 | PropertyInfo* XlibTouchpad::getDevProperty(const QLatin1String& propName) | ||||
179 | { | ||||
180 | if (m_props.contains(propName)) { | ||||
181 | return &m_props[propName]; | ||||
182 | } | ||||
183 | | ||||
184 | if (!m_atoms.contains(propName) || !m_atoms[propName]) { | ||||
185 | return 0; | ||||
186 | } | ||||
187 | | ||||
188 | xcb_atom_t prop = m_atoms[propName]->atom(); | ||||
189 | if (!prop) { | ||||
190 | return 0; | ||||
191 | } | ||||
192 | | ||||
193 | PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom()); | ||||
194 | if (!p.b && !p.f && !p.i) { | ||||
195 | return 0; | ||||
196 | } | ||||
197 | return &m_props.insert(propName, p).value(); | ||||
198 | } | ||||
199 | | ||||
200 | bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value) | ||||
201 | { | ||||
202 | QLatin1String propName(par->prop_name); | ||||
203 | PropertyInfo *p = getDevProperty(propName); | ||||
204 | if (!p || par->prop_offset >= p->nitems) { | ||||
205 | return false; | ||||
206 | } | ||||
207 | | ||||
208 | QVariant converted(value); | ||||
209 | QVariant::Type convType = QVariant::Int; | ||||
210 | if (p->f) { | ||||
211 | convType = QVariant::Double; | ||||
212 | } else if (value.type() == QVariant::Double) { | ||||
213 | converted = QVariant(qRound(static_cast<qreal>(value.toDouble()))); | ||||
214 | } | ||||
215 | | ||||
216 | if (!converted.convert(convType)) { | ||||
217 | return false; | ||||
218 | } | ||||
219 | | ||||
220 | if (converted == p->value(par->prop_offset)) { | ||||
221 | return true; | ||||
222 | } | ||||
223 | | ||||
224 | if (p->b) { | ||||
225 | p->b[par->prop_offset] = static_cast<char>(converted.toInt()); | ||||
226 | } else if (p->i) { | ||||
227 | p->i[par->prop_offset] = converted.toInt(); | ||||
228 | } else if (p->f) { | ||||
229 | p->f[par->prop_offset] = converted.toDouble(); | ||||
230 | } | ||||
231 | | ||||
232 | m_changed.insert(propName); | ||||
233 | return true; | ||||
234 | } | ||||
235 | | ||||
236 | | ||||
237 | void XlibTouchpad::setEnabled(bool enable) | ||||
238 | { | ||||
239 | PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); | ||||
240 | if (enabled.b && *(enabled.b) != enable) { | ||||
241 | *(enabled.b) = enable; | ||||
242 | enabled.set(); | ||||
243 | } | ||||
244 | | ||||
245 | flush(); | ||||
246 | } | ||||
247 | | ||||
248 | bool XlibTouchpad::enabled() | ||||
249 | { | ||||
250 | PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); | ||||
251 | return enabled.value(0).toBool(); | ||||
252 | } | ||||
253 | | ||||
254 | | ||||
255 | void XlibTouchpad::setTouchpadOff(int touchpadOff) | ||||
256 | { | ||||
257 | PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0); | ||||
258 | if (off.b && *(off.b) != touchpadOff) { | ||||
259 | *(off.b) = touchpadOff; | ||||
260 | off.set(); | ||||
261 | } | ||||
262 | | ||||
263 | flush(); | ||||
264 | } | ||||
265 | | ||||
266 | int XlibTouchpad::touchpadOff() | ||||
267 | { | ||||
268 | PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0); | ||||
269 | return off.value(0).toInt(); | ||||
270 | } | ||||
271 | | ||||
272 | XcbAtom& XlibTouchpad::touchpadOffAtom() | ||||
273 | { | ||||
274 | return m_touchpadOffAtom; | ||||
275 | } | ||||
276 | | ||||
277 | const Parameter* XlibTouchpad::findParameter(const QString& name) | ||||
278 | { | ||||
279 | for (const Parameter *par = m_paramList; par->name; par++) { | ||||
280 | if (name == par->name) { | ||||
281 | return par; | ||||
282 | } | ||||
283 | } | ||||
284 | return 0; | ||||
285 | } |