Changeset View
Changeset View
Standalone View
Standalone View
kcms/input/backends/x11/x11_evdev_backend.cpp
- This file was copied from kcms/input/backends/x11/x11_backend.cpp.
Show All 11 Lines | |||||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. | ||
14 | * | 14 | * | ||
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | #include "x11_backend.h" | 20 | #include "x11_evdev_backend.h" | ||
21 | 21 | | |||
22 | #include <config-X11.h> | 22 | #include <config-X11.h> | ||
23 | 23 | | |||
24 | #include <QFile> | 24 | #include <QFile> | ||
25 | #include <QX11Info> | 25 | #include <QX11Info> | ||
26 | #include <KLocalizedString> | 26 | #include <KLocalizedString> | ||
27 | #include <evdev-properties.h> | 27 | #include <evdev-properties.h> | ||
28 | #include <libinput-properties.h> | | |||
29 | 28 | | |||
30 | #include <X11/X.h> | 29 | #include <X11/X.h> | ||
31 | #include <X11/Xlib.h> | 30 | #include <X11/Xlib.h> | ||
32 | #include <X11/Xatom.h> | 31 | #include <X11/Xatom.h> | ||
33 | #include <X11/extensions/XInput2.h> | 32 | #include <X11/extensions/XInput2.h> | ||
34 | #include <X11/extensions/XI.h> | 33 | #include <X11/extensions/XI.h> | ||
35 | #include <X11/Xutil.h> | 34 | #include <X11/Xutil.h> | ||
36 | #ifdef HAVE_XCURSOR | 35 | #ifdef HAVE_XCURSOR | ||
37 | #include <X11/Xcursor/Xcursor.h> | 36 | #include <X11/Xcursor/Xcursor.h> | ||
38 | #include <X11/extensions/XInput.h> | 37 | #include <X11/extensions/XInput.h> | ||
39 | #endif | 38 | #endif | ||
40 | 39 | | |||
41 | static const char PROFILE_NONE[] = I18N_NOOP("None"); | | |||
42 | static const char PROFILE_ADAPTIVE[] = I18N_NOOP("Adaptive"); | | |||
43 | static const char PROFILE_FLAT[] = I18N_NOOP("Flat"); | | |||
44 | | ||||
45 | struct ScopedXDeleter { | 40 | struct ScopedXDeleter { | ||
46 | static inline void cleanup(void* pointer) | 41 | static inline void cleanup(void* pointer) | ||
47 | { | 42 | { | ||
48 | if (pointer) { | 43 | if (pointer) { | ||
49 | XFree(pointer); | 44 | XFree(pointer); | ||
50 | } | 45 | } | ||
51 | } | 46 | } | ||
52 | }; | 47 | }; | ||
53 | 48 | | |||
54 | template<typename Callback> | 49 | template<typename Callback> | ||
55 | static void XI2ForallPointerDevices(Display* dpy, const Callback& callback) | | |||
56 | { | | |||
57 | int ndevices_return; | | |||
58 | XIDeviceInfo* info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return); | | |||
59 | if (!info) { | | |||
60 | return; | | |||
61 | } | | |||
62 | for (int i = 0; i < ndevices_return; ++i) { | | |||
63 | if ((info + i)->use == XISlavePointer) { | | |||
64 | callback(info + i); | | |||
65 | } | | |||
66 | } | | |||
67 | XIFreeDeviceInfo(info); | | |||
68 | } | | |||
69 | | ||||
70 | template<typename Callback> | | |||
71 | static void XIForallPointerDevices(Display* dpy, const Callback& callback) | 50 | static void XIForallPointerDevices(Display* dpy, const Callback& callback) | ||
72 | { | 51 | { | ||
73 | int ndevices_return; | 52 | int ndevices_return; | ||
74 | XDeviceInfo* info = XListInputDevices(dpy, &ndevices_return); | 53 | XDeviceInfo* info = XListInputDevices(dpy, &ndevices_return); | ||
75 | if (!info) { | 54 | if (!info) { | ||
76 | return; | 55 | return; | ||
77 | } | 56 | } | ||
78 | for (int i = 0; i < ndevices_return; ++i) { | 57 | for (int i = 0; i < ndevices_return; ++i) { | ||
79 | if (info[i].use == IsXPointer || info[i].use == IsXExtensionPointer) { | 58 | if (info[i].use == IsXPointer || info[i].use == IsXExtensionPointer) { | ||
80 | callback(info + i); | 59 | callback(info + i); | ||
81 | } | 60 | } | ||
82 | } | 61 | } | ||
83 | XFreeDeviceList(info); | 62 | XFreeDeviceList(info); | ||
84 | } | 63 | } | ||
85 | 64 | | |||
86 | X11Backend::X11Backend(QObject* parent) | 65 | X11EvdevBackend::X11EvdevBackend(QObject* parent) | ||
87 | : InputBackend(parent) | 66 | : X11Backend(parent) | ||
88 | { | 67 | { | ||
89 | m_mode = InputBackendMode::XEvdev; | 68 | m_mode = InputBackendMode::XEvdev; | ||
90 | | ||||
91 | m_platformX11 = QX11Info::isPlatformX11(); | | |||
92 | if (m_platformX11) { | | |||
93 | m_dpy = QX11Info::display(); | | |||
94 | } else { | | |||
95 | // TODO: remove this - not needed anymore with Wayland backend! | | |||
96 | // let's hope we have a compatibility system like Xwayland ready | | |||
97 | m_dpy = XOpenDisplay(nullptr); | | |||
98 | } | | |||
99 | m_settings = new EvdevSettings(); | 69 | m_settings = new EvdevSettings(); | ||
100 | initAtom(); | 70 | initAtom(); | ||
101 | } | 71 | } | ||
102 | 72 | | |||
103 | void X11Backend::initAtom() | 73 | void X11EvdevBackend::initAtom() | ||
104 | { | 74 | { | ||
105 | if (!m_dpy) { | 75 | if (!m_dpy) { | ||
106 | return; | 76 | return; | ||
107 | } | 77 | } | ||
108 | 78 | | |||
109 | m_libinputAccelProfileAvailableAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, True); | | |||
110 | m_libinputAccelProfileEnabledAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); | | |||
111 | m_libinputNaturalScrollAtom = XInternAtom(m_dpy, LIBINPUT_PROP_NATURAL_SCROLL, True); | | |||
112 | | ||||
113 | m_evdevScrollDistanceAtom = XInternAtom(m_dpy, EVDEV_PROP_SCROLL_DISTANCE, True); | 79 | m_evdevScrollDistanceAtom = XInternAtom(m_dpy, EVDEV_PROP_SCROLL_DISTANCE, True); | ||
114 | m_evdevWheelEmulationAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL, True); | 80 | m_evdevWheelEmulationAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL, True); | ||
115 | m_evdevWheelEmulationAxesAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL_AXES, True); | 81 | m_evdevWheelEmulationAxesAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL_AXES, True); | ||
116 | 82 | | |||
117 | m_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True); | 83 | m_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True); | ||
118 | } | 84 | } | ||
119 | 85 | | |||
120 | 86 | | |||
121 | X11Backend::~X11Backend() | 87 | X11EvdevBackend::~X11EvdevBackend() | ||
122 | { | 88 | { | ||
123 | if (!m_platformX11 && m_dpy) { | | |||
124 | XCloseDisplay(m_dpy); | | |||
125 | } | | |||
126 | delete m_settings; | 89 | delete m_settings; | ||
127 | } | 90 | } | ||
128 | 91 | | |||
129 | bool X11Backend::supportScrollPolarity() | 92 | bool X11EvdevBackend::supportScrollPolarity() | ||
130 | { | 93 | { | ||
131 | return m_numButtons >= 5; | 94 | return m_numButtons >= 5; | ||
132 | } | 95 | } | ||
133 | 96 | | |||
134 | QStringList X11Backend::supportedAccelerationProfiles() | 97 | double X11EvdevBackend::accelRate() | ||
135 | { | | |||
136 | return m_supportedAccelerationProfiles; | | |||
137 | } | | |||
138 | | ||||
139 | QString X11Backend::accelerationProfile() | | |||
140 | { | | |||
141 | return m_accelerationProfile; | | |||
142 | } | | |||
143 | | ||||
144 | double X11Backend::accelRate() | | |||
145 | { | 98 | { | ||
146 | return m_accelRate; | 99 | return m_accelRate; | ||
147 | } | 100 | } | ||
148 | 101 | | |||
149 | Handed X11Backend::handed() | 102 | Handed X11EvdevBackend::handed() | ||
150 | { | 103 | { | ||
151 | return m_handed; | 104 | return m_handed; | ||
152 | } | 105 | } | ||
153 | 106 | | |||
154 | int X11Backend::threshold() | 107 | int X11EvdevBackend::threshold() | ||
155 | { | 108 | { | ||
156 | return m_threshold; | 109 | return m_threshold; | ||
157 | } | 110 | } | ||
158 | 111 | | |||
159 | void X11Backend::load() | 112 | void X11EvdevBackend::load() | ||
160 | { | 113 | { | ||
161 | if (!m_dpy) { | 114 | if (!m_dpy) { | ||
162 | return; | 115 | return; | ||
163 | } | 116 | } | ||
164 | 117 | | |||
165 | m_accelRate = 1.0; | 118 | m_accelRate = 1.0; | ||
166 | int accel_num, accel_den; | 119 | int accel_num, accel_den; | ||
167 | XGetPointerControl(m_dpy, &accel_num, &accel_den, &m_threshold); | 120 | XGetPointerControl(m_dpy, &accel_num, &accel_den, &m_threshold); | ||
Show All 16 Lines | 136 | } else if (m_numButtons >= 3) { | |||
184 | m_middleButton = map[1]; | 137 | m_middleButton = map[1]; | ||
185 | if (map[0] == 1 && map[2] == 3) { | 138 | if (map[0] == 1 && map[2] == 3) { | ||
186 | m_handed = Handed::Right; | 139 | m_handed = Handed::Right; | ||
187 | } else if (map[0] == 3 && map[2] == 1) { | 140 | } else if (map[0] == 3 && map[2] == 1) { | ||
188 | m_handed = Handed::Left; | 141 | m_handed = Handed::Left; | ||
189 | } | 142 | } | ||
190 | } | 143 | } | ||
191 | 144 | | |||
192 | m_supportedAccelerationProfiles.clear(); | | |||
193 | bool adaptiveAvailable = false; | | |||
194 | bool flatAvailable = false; | | |||
195 | bool adaptiveEnabled = false; | | |||
196 | bool flatEnabled = false; | | |||
197 | if (m_libinputAccelProfileAvailableAtom != None && m_libinputAccelProfileEnabledAtom != None) { | | |||
198 | XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { | | |||
199 | int deviceid = info->deviceid; | | |||
200 | Status status; | | |||
201 | Atom type_return; | | |||
202 | int format_return; | | |||
203 | unsigned long num_items_return; | | |||
204 | unsigned long bytes_after_return; | | |||
205 | | ||||
206 | unsigned char *_data = nullptr; | | |||
207 | //data returned is an 2 byte boolean | | |||
208 | status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2, | | |||
209 | False, XA_INTEGER, &type_return, &format_return, | | |||
210 | &num_items_return, &bytes_after_return, &_data); | | |||
211 | QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data); | | |||
212 | _data = nullptr; | | |||
213 | if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { | | |||
214 | return; | | |||
215 | } | | |||
216 | adaptiveAvailable = adaptiveAvailable || data[0]; | | |||
217 | flatAvailable = flatAvailable || data[1]; | | |||
218 | | ||||
219 | //data returned is an 2 byte boolean | | |||
220 | status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, 0, 2, | | |||
221 | False, XA_INTEGER, &type_return, &format_return, | | |||
222 | &num_items_return, &bytes_after_return, &_data); | | |||
223 | data.reset(_data); | | |||
224 | _data = nullptr; | | |||
225 | if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { | | |||
226 | return; | | |||
227 | } | | |||
228 | adaptiveEnabled = adaptiveEnabled || data[0]; | | |||
229 | flatEnabled = flatEnabled || data[1]; | | |||
230 | }); | | |||
231 | } | | |||
232 | | ||||
233 | if (adaptiveAvailable) { | | |||
234 | m_supportedAccelerationProfiles << PROFILE_ADAPTIVE; | | |||
235 | } | | |||
236 | if (flatAvailable) { | | |||
237 | m_supportedAccelerationProfiles << PROFILE_FLAT; | | |||
238 | } | | |||
239 | if (adaptiveAvailable || flatAvailable) { | | |||
240 | m_supportedAccelerationProfiles << PROFILE_NONE; | | |||
241 | } | | |||
242 | | ||||
243 | m_accelerationProfile = PROFILE_NONE; | | |||
244 | if (adaptiveEnabled) { | | |||
245 | m_accelerationProfile = PROFILE_ADAPTIVE; | | |||
246 | } else if (flatEnabled) { | | |||
247 | m_accelerationProfile = PROFILE_FLAT; | | |||
248 | } | | |||
249 | | ||||
250 | m_settings->load(this); | 145 | m_settings->load(this); | ||
251 | } | 146 | } | ||
252 | 147 | | |||
253 | void X11Backend::apply(bool force) | 148 | void X11EvdevBackend::apply(bool force) | ||
254 | { | 149 | { | ||
255 | // 256 might seems extreme, but X has already been known to return 32, | 150 | // 256 might seems extreme, but X has already been known to return 32, | ||
256 | // and we don't want to truncate things. Xlib limits the table to 256 bytes, | 151 | // and we don't want to truncate things. Xlib limits the table to 256 bytes, | ||
257 | // so it's a good upper bound.. | 152 | // so it's a good upper bound.. | ||
258 | unsigned char map[256]; | 153 | unsigned char map[256]; | ||
259 | XGetPointerMapping(m_dpy, map, 256); | 154 | XGetPointerMapping(m_dpy, map, 256); | ||
260 | 155 | | |||
261 | if (m_settings->handedEnabled && (m_settings->handedNeedsApply || force)) { | 156 | if (m_settings->handedEnabled && (m_settings->handedNeedsApply || force)) { | ||
Show All 29 Lines | |||||
291 | 186 | | |||
292 | // apply reverseScrollPolarity for all non-touchpad pointer, touchpad | 187 | // apply reverseScrollPolarity for all non-touchpad pointer, touchpad | ||
293 | // are belong to kcm touchpad. | 188 | // are belong to kcm touchpad. | ||
294 | XIForallPointerDevices(m_dpy, [this](XDeviceInfo * info) { | 189 | XIForallPointerDevices(m_dpy, [this](XDeviceInfo * info) { | ||
295 | int deviceid = info->id; | 190 | int deviceid = info->id; | ||
296 | if (info->type == m_touchpadAtom) { | 191 | if (info->type == m_touchpadAtom) { | ||
297 | return; | 192 | return; | ||
298 | } | 193 | } | ||
299 | if (libinputApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity)) { | | |||
300 | return; | | |||
301 | } | | |||
302 | evdevApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity); | 194 | evdevApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity); | ||
303 | }); | 195 | }); | ||
304 | 196 | | |||
305 | } | 197 | } | ||
306 | 198 | | |||
307 | XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { | | |||
308 | libinputApplyAccelerationProfile(info->deviceid, m_settings->currentAccelProfile); | | |||
309 | }); | | |||
310 | | ||||
311 | XChangePointerControl(m_dpy, | 199 | XChangePointerControl(m_dpy, | ||
312 | true, true, int(qRound(m_settings->accelRate * 10)), 10, m_settings->thresholdMove); | 200 | true, true, int(qRound(m_settings->accelRate * 10)), 10, m_settings->thresholdMove); | ||
313 | 201 | | |||
314 | XFlush(m_dpy); | 202 | XFlush(m_dpy); | ||
315 | } | 203 | } | ||
316 | 204 | | |||
317 | QString X11Backend::currentCursorTheme() | 205 | bool X11EvdevBackend::evdevApplyReverseScroll(int deviceid, bool reverse) | ||
318 | { | | |||
319 | if (!m_dpy) { | | |||
320 | return QString(); | | |||
321 | } | | |||
322 | | ||||
323 | QByteArray name = XGetDefault(m_dpy, "Xcursor", "theme"); | | |||
324 | #ifdef HAVE_XCURSOR | | |||
325 | if (name.isEmpty()) { | | |||
326 | name = QByteArray(XcursorGetTheme(m_dpy)); | | |||
327 | } | | |||
328 | #endif | | |||
329 | return QFile::decodeName(name); | | |||
330 | } | | |||
331 | | ||||
332 | void X11Backend::applyCursorTheme(const QString& theme, int size) | | |||
333 | { | | |||
334 | #ifdef HAVE_XCURSOR | | |||
335 | | ||||
336 | // Apply the KDE cursor theme to ourselves | | |||
337 | if (m_dpy) { | | |||
338 | return; | | |||
339 | } | | |||
340 | if (!theme.isEmpty()) { | | |||
341 | XcursorSetTheme(m_dpy, QFile::encodeName(theme)); | | |||
342 | } | | |||
343 | | ||||
344 | if (size >= 0) { | | |||
345 | XcursorSetDefaultSize(m_dpy, size); | | |||
346 | } | | |||
347 | | ||||
348 | // Load the default cursor from the theme and apply it to the root window. | | |||
349 | Cursor handle = XcursorLibraryLoadCursor(m_dpy, "left_ptr"); | | |||
350 | XDefineCursor(m_dpy, DefaultRootWindow(m_dpy), handle); | | |||
351 | XFreeCursor(m_dpy, handle); // Don't leak the cursor | | |||
352 | XFlush(m_dpy); | | |||
353 | #endif | | |||
354 | } | | |||
355 | | ||||
356 | bool X11Backend::evdevApplyReverseScroll(int deviceid, bool reverse) | | |||
357 | { | 206 | { | ||
358 | // Check atom availability first. | 207 | // Check atom availability first. | ||
359 | if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None || | 208 | if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None || | ||
360 | m_evdevWheelEmulationAxesAtom == None) { | 209 | m_evdevWheelEmulationAxesAtom == None) { | ||
361 | return false; | 210 | return false; | ||
362 | } | 211 | } | ||
363 | Status status; | 212 | Status status; | ||
364 | Atom type_return; | 213 | Atom type_return; | ||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Line(s) | 253 | if (status == Success && type_return == XA_INTEGER && | |||
417 | XIChangeProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, XA_INTEGER, | 266 | XIChangeProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, XA_INTEGER, | ||
418 | 8, XIPropModeReplace, data.data(), 4); | 267 | 8, XIPropModeReplace, data.data(), 4); | ||
419 | } | 268 | } | ||
420 | } | 269 | } | ||
421 | 270 | | |||
422 | return true; | 271 | return true; | ||
423 | } | 272 | } | ||
424 | 273 | | |||
425 | bool X11Backend::libinputApplyReverseScroll(int deviceid, bool reverse) | 274 | void X11EvdevBackend::kcmInit() | ||
426 | { | | |||
427 | // Check atom availability first. | | |||
428 | if (m_libinputNaturalScrollAtom == None) { | | |||
429 | return false; | | |||
430 | } | | |||
431 | Status status; | | |||
432 | Atom type_return; | | |||
433 | int format_return; | | |||
434 | unsigned long num_items_return; | | |||
435 | unsigned long bytes_after_return; | | |||
436 | | ||||
437 | unsigned char *_data = nullptr; | | |||
438 | //data returned is an 1 byte boolean | | |||
439 | status = XIGetProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, 0, 1, | | |||
440 | False, XA_INTEGER, &type_return, &format_return, | | |||
441 | &num_items_return, &bytes_after_return, &_data); | | |||
442 | if (status != Success) { | | |||
443 | return false; | | |||
444 | } | | |||
445 | QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data); | | |||
446 | _data = nullptr; | | |||
447 | if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 1) { | | |||
448 | return false; | | |||
449 | } | | |||
450 | unsigned char natural = reverse ? 1 : 0; | | |||
451 | XIChangeProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, XA_INTEGER, | | |||
452 | 8, XIPropModeReplace, &natural, 1); | | |||
453 | return true; | | |||
454 | } | | |||
455 | | ||||
456 | void X11Backend::libinputApplyAccelerationProfile(int deviceid, QString profile) | | |||
457 | { | 275 | { | ||
458 | // Check atom availability first. | 276 | m_settings->load(this); | ||
459 | if (m_libinputAccelProfileAvailableAtom == None || m_libinputAccelProfileEnabledAtom == None) { | 277 | apply(true); // force | ||
460 | return; | 278 | X11Backend::kcmInit(); | ||
461 | } | | |||
462 | | ||||
463 | unsigned char profileData[2]; | | |||
464 | if (profile == PROFILE_NONE) { | | |||
465 | profileData[0] = profileData[1] = 0; | | |||
466 | } else if (profile == PROFILE_ADAPTIVE) { | | |||
467 | profileData[0] = 1; | | |||
468 | profileData[1] = 0; | | |||
469 | } else if (profile == PROFILE_FLAT) { | | |||
470 | profileData[0] = 0; | | |||
471 | profileData[1] = 1; | | |||
472 | } | | |||
473 | Status status; | | |||
474 | Atom type_return; | | |||
475 | int format_return; | | |||
476 | unsigned long num_items_return; | | |||
477 | unsigned long bytes_after_return; | | |||
478 | | ||||
479 | unsigned char *_data = nullptr; | | |||
480 | //data returned is an 1 byte boolean | | |||
481 | status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2, | | |||
482 | False, XA_INTEGER, &type_return, &format_return, | | |||
483 | &num_items_return, &bytes_after_return, &_data); | | |||
484 | if (status != Success) { | | |||
485 | return; | | |||
486 | } | | |||
487 | QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data); | | |||
488 | _data = nullptr; | | |||
489 | if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { | | |||
490 | return; | | |||
491 | } | | |||
492 | // Check availability for profile. | | |||
493 | if (profileData[0] > data[0] || profileData[1] > data[1]) { | | |||
494 | return; | | |||
495 | } | | |||
496 | XIChangeProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, XA_INTEGER, | | |||
497 | 8, XIPropModeReplace, profileData, 2); | | |||
498 | } | 279 | } |