diff --git a/kcms/keys/kglobalshortcutseditor.ui b/kcms/keys/kglobalshortcutseditor.ui
index 32ca2f0e1..f389a9c9a 100644
--- a/kcms/keys/kglobalshortcutseditor.ui
+++ b/kcms/keys/kglobalshortcutseditor.ui
@@ -1,118 +1,130 @@
KGlobalShortcutsEditor
0
0
660
572
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
-
-
0
0
Component:
-
0
0
-
-
0
0
+
+ QAbstractItemView::NoEditTriggers
+
QAbstractItemView::ScrollPerPixel
-
- QAbstractItemView::NoEditTriggers
-
-
-
Add a new shortcut to an Application...
...
-
Remove the selected component
...
-
Qt::Horizontal
40
20
-
File
KCategorizedView
QListView
menu_button
diff --git a/kcms/mouse/backends/x11/x11_evdev_backend.cpp b/kcms/mouse/backends/x11/x11_evdev_backend.cpp
index b1cb43750..07d0be1b7 100644
--- a/kcms/mouse/backends/x11/x11_evdev_backend.cpp
+++ b/kcms/mouse/backends/x11/x11_evdev_backend.cpp
@@ -1,279 +1,279 @@
/*
* Copyright 2017 Xuetian Weng
* Copyright 2018 Roman Gilg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "x11_evdev_backend.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_XCURSOR
#include
#include
#endif
struct ScopedXDeleter {
static inline void cleanup(void* pointer)
{
if (pointer) {
XFree(pointer);
}
}
};
template
static void XIForallPointerDevices(Display* dpy, const Callback& callback)
{
int ndevices_return;
XDeviceInfo* info = XListInputDevices(dpy, &ndevices_return);
if (!info) {
return;
}
for (int i = 0; i < ndevices_return; ++i) {
if (info[i].use == IsXPointer || info[i].use == IsXExtensionPointer) {
callback(info + i);
}
}
XFreeDeviceList(info);
}
X11EvdevBackend::X11EvdevBackend(QObject* parent)
: X11Backend(parent)
{
m_mode = InputBackendMode::XEvdev;
m_settings = new EvdevSettings();
initAtom();
}
void X11EvdevBackend::initAtom()
{
if (!m_dpy) {
return;
}
m_evdevScrollDistanceAtom = XInternAtom(m_dpy, EVDEV_PROP_SCROLL_DISTANCE, True);
m_evdevWheelEmulationAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL, True);
m_evdevWheelEmulationAxesAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL_AXES, True);
m_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True);
}
X11EvdevBackend::~X11EvdevBackend()
{
delete m_settings;
}
bool X11EvdevBackend::supportScrollPolarity()
{
return m_numButtons >= 5;
}
double X11EvdevBackend::accelRate()
{
return m_accelRate;
}
Handed X11EvdevBackend::handed()
{
return m_handed;
}
int X11EvdevBackend::threshold()
{
return m_threshold;
}
void X11EvdevBackend::load()
{
if (!m_dpy) {
return;
}
m_accelRate = 1.0;
int accel_num, accel_den;
XGetPointerControl(m_dpy, &accel_num, &accel_den, &m_threshold);
m_accelRate = double(accel_num) / double(accel_den);
// get settings from X server
unsigned char map[256];
m_numButtons = XGetPointerMapping(m_dpy, map, 256);
m_middleButton = -1;
m_handed = Handed::NotSupported;
// ## keep this in sync with KGlobalSettings::mouseSettings
if (m_numButtons == 2) {
if (map[0] == 1 && map[1] == 2) {
m_handed = Handed::Right;
} else if (map[0] == 2 && map[1] == 1) {
m_handed = Handed::Left;
}
} else if (m_numButtons >= 3) {
m_middleButton = map[1];
if (map[0] == 1 && map[2] == 3) {
m_handed = Handed::Right;
} else if (map[0] == 3 && map[2] == 1) {
m_handed = Handed::Left;
}
}
m_settings->load(this);
}
void X11EvdevBackend::apply(bool force)
{
// 256 might seems extreme, but X has already been known to return 32,
// and we don't want to truncate things. Xlib limits the table to 256 bytes,
// so it's a good upper bound..
unsigned char map[256];
XGetPointerMapping(m_dpy, map, 256);
if (m_settings->handedEnabled && (m_settings->handedNeedsApply || force)) {
if (m_numButtons == 1) {
map[0] = (unsigned char) 1;
} else if (m_numButtons == 2) {
if (m_settings->handed == Handed::Right) {
map[0] = (unsigned char) 1;
map[1] = (unsigned char) 3;
} else {
map[0] = (unsigned char) 3;
map[1] = (unsigned char) 1;
}
} else { // 3 buttons and more
if (m_settings->handed == Handed::Right) {
map[0] = (unsigned char) 1;
map[1] = (unsigned char) m_middleButton;
map[2] = (unsigned char) 3;
} else {
map[0] = (unsigned char) 3;
map[1] = (unsigned char) m_middleButton;
map[2] = (unsigned char) 1;
}
}
int retval;
if (m_numButtons >= 1) {
while ((retval = XSetPointerMapping(m_dpy, map,
m_numButtons)) == MappingBusy)
/* keep trying until the pointer is free */
{ };
}
// apply reverseScrollPolarity for all non-touchpad pointer, touchpad
// are belong to kcm touchpad.
XIForallPointerDevices(m_dpy, [this](XDeviceInfo * info) {
int deviceid = info->id;
if (info->type == m_touchpadAtom) {
return;
}
evdevApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity);
});
}
XChangePointerControl(m_dpy,
true, true, int(qRound(m_settings->accelRate * 10)), 10, m_settings->thresholdMove);
XFlush(m_dpy);
}
bool X11EvdevBackend::evdevApplyReverseScroll(int deviceid, bool reverse)
{
// Check atom availability first.
if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None ||
m_evdevWheelEmulationAxesAtom == None) {
return false;
}
Status status;
Atom type_return;
int format_return;
unsigned long num_items_return;
unsigned long bytes_after_return;
unsigned char* _data = nullptr;
//data returned is an 1 byte boolean
status = XIGetProperty(m_dpy, deviceid, m_evdevWheelEmulationAtom, 0, 1,
False, XA_INTEGER, &type_return, &format_return,
&num_items_return, &bytes_after_return, &_data);
QScopedArrayPointer data(_data);
_data = nullptr;
if (status != Success) {
return false;
}
// pointer device without wheel emulation
if (type_return != XA_INTEGER || data == NULL || *data == False) {
status = XIGetProperty(m_dpy, deviceid, m_evdevScrollDistanceAtom, 0, 3,
False, XA_INTEGER, &type_return, &format_return,
&num_items_return, &bytes_after_return, &_data);
data.reset(_data);
_data = nullptr;
// negate scroll distance
if (status == Success && type_return == XA_INTEGER &&
format_return == 32 && num_items_return == 3) {
int32_t* vals = (int32_t*)data.data();
for (unsigned long i = 0; i < num_items_return; ++i) {
int32_t val = *(vals + i);
*(vals + i) = (int32_t)(reverse ? -abs(val) : abs(val));
}
XIChangeProperty(m_dpy, deviceid, m_evdevScrollDistanceAtom, XA_INTEGER,
32, XIPropModeReplace, data.data(), 3);
}
} else { // wheel emulation used, reverse wheel axes
status = XIGetProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, 0, 4,
False, XA_INTEGER, &type_return, &format_return,
&num_items_return, &bytes_after_return, &_data);
data.reset(_data);
_data = nullptr;
if (status == Success && type_return == XA_INTEGER &&
format_return == 8 && num_items_return == 4) {
// when scroll direction is not reversed,
// up button id should be smaller than down button id,
// up/left are odd elements, down/right are even elements
for (int i = 0; i < 2; ++i) {
unsigned char odd = data[i * 2];
unsigned char even = data[i * 2 + 1];
unsigned char max_elem = std::max(odd, even);
unsigned char min_elem = std::min(odd, even);
data[i * 2] = reverse ? max_elem : min_elem;
data[i * 2 + 1] = reverse ? min_elem : max_elem;
}
XIChangeProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, XA_INTEGER,
8, XIPropModeReplace, data.data(), 4);
}
}
return true;
}
void X11EvdevBackend::kcmInit()
{
- m_settings->load(this);
+ load();
apply(true); // force
X11Backend::kcmInit();
}