mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-23 15:45:53 +00:00
258 lines
6.3 KiB
C++
258 lines
6.3 KiB
C++
|
#include <cmath>
|
||
|
|
||
|
#include "xlibtouchpad.h"
|
||
|
#include <X11/Xlib-xcb.h>
|
||
|
#include <X11/extensions/XInput.h>
|
||
|
#include <X11/extensions/XInput2.h>
|
||
|
#include <xserver-properties.h>
|
||
|
|
||
|
static QVariant negateVariant(const QVariant &value)
|
||
|
{
|
||
|
if (value.type() == QVariant::Double) {
|
||
|
return QVariant(-value.toDouble());
|
||
|
} else if (value.type() == QVariant::Int) {
|
||
|
return QVariant(-value.toInt());
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
XlibTouchpad::XlibTouchpad(Display *display, int deviceId)
|
||
|
: m_display(display)
|
||
|
, m_connection(XGetXCBConnection(display))
|
||
|
, m_deviceId(deviceId)
|
||
|
{
|
||
|
m_floatType.intern(m_connection, "FLOAT");
|
||
|
m_enabledAtom.intern(m_connection, XI_PROP_ENABLED);
|
||
|
}
|
||
|
|
||
|
bool XlibTouchpad::applyConfig(const QVariantHash &p)
|
||
|
{
|
||
|
m_props.clear();
|
||
|
|
||
|
bool error = false;
|
||
|
for (const QString &name : qAsConst(m_supported)) {
|
||
|
QVariantHash::ConstIterator i = p.find(name);
|
||
|
if (i == p.end()) {
|
||
|
continue;
|
||
|
}
|
||
|
const Parameter *par = findParameter(name);
|
||
|
if (par) {
|
||
|
QVariant value(i.value());
|
||
|
|
||
|
double k = getPropertyScale(name);
|
||
|
if (k != 1.0) {
|
||
|
bool ok = false;
|
||
|
value = QVariant(value.toDouble(&ok) * k);
|
||
|
if (!ok) {
|
||
|
error = true;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_negate.contains(name)) {
|
||
|
QVariantHash::ConstIterator i = p.find(m_negate[name]);
|
||
|
if (i != p.end() && i.value().toBool()) {
|
||
|
value = negateVariant(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (name == "CoastingSpeed") {
|
||
|
QVariantHash::ConstIterator coastingEnabled = p.find("Coasting");
|
||
|
if (coastingEnabled != p.end() && !coastingEnabled.value().toBool()) {
|
||
|
value = QVariant(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!setParameter(par, value)) {
|
||
|
error = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
flush();
|
||
|
|
||
|
return !error;
|
||
|
}
|
||
|
|
||
|
bool XlibTouchpad::getConfig(QVariantHash &p)
|
||
|
{
|
||
|
if (m_supported.isEmpty()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
m_props.clear();
|
||
|
|
||
|
bool error = false;
|
||
|
for (const QString &name : qAsConst(m_supported)) {
|
||
|
const Parameter *par = findParameter(name);
|
||
|
if (!par) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
QVariant value(getParameter(par));
|
||
|
if (!value.isValid()) {
|
||
|
error = true;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
double k = getPropertyScale(name);
|
||
|
if (k != 1.0) {
|
||
|
bool ok = false;
|
||
|
value = QVariant(value.toDouble(&ok) / k);
|
||
|
if (!ok) {
|
||
|
error = true;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_negate.contains(name)) {
|
||
|
bool negative = value.toDouble() < 0.0;
|
||
|
p[m_negate[name]] = QVariant(negative);
|
||
|
if (negative) {
|
||
|
value = negateVariant(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (name == "CoastingSpeed") {
|
||
|
bool coasting = value.toDouble() != 0.0;
|
||
|
p["Coasting"] = QVariant(coasting);
|
||
|
if (!coasting) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p[name] = value;
|
||
|
}
|
||
|
|
||
|
return !error;
|
||
|
}
|
||
|
|
||
|
void XlibTouchpad::loadSupportedProperties(const Parameter *props)
|
||
|
{
|
||
|
m_paramList = props;
|
||
|
for (const Parameter *param = props; param->name; param++) {
|
||
|
QLatin1String name(param->prop_name);
|
||
|
|
||
|
if (!m_atoms.contains(name)) {
|
||
|
m_atoms.insert(name, QSharedPointer<XcbAtom>(new XcbAtom(m_connection, param->prop_name)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (const Parameter *p = props; p->name; p++) {
|
||
|
if (getParameter(p).isValid()) {
|
||
|
m_supported.append(p->name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QVariant XlibTouchpad::getParameter(const Parameter *par)
|
||
|
{
|
||
|
PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name));
|
||
|
if (!p || par->prop_offset >= p->nitems) {
|
||
|
return QVariant();
|
||
|
}
|
||
|
|
||
|
return p->value(par->prop_offset);
|
||
|
}
|
||
|
|
||
|
void XlibTouchpad::flush()
|
||
|
{
|
||
|
for (const QLatin1String &name : qAsConst(m_changed)) {
|
||
|
m_props[name].set();
|
||
|
}
|
||
|
m_changed.clear();
|
||
|
|
||
|
XFlush(m_display);
|
||
|
}
|
||
|
|
||
|
double XlibTouchpad::getPropertyScale(const QString &name) const
|
||
|
{
|
||
|
Q_UNUSED(name);
|
||
|
return 1.0;
|
||
|
}
|
||
|
|
||
|
PropertyInfo *XlibTouchpad::getDevProperty(const QLatin1String &propName)
|
||
|
{
|
||
|
if (m_props.contains(propName)) {
|
||
|
return &m_props[propName];
|
||
|
}
|
||
|
|
||
|
if (!m_atoms.contains(propName) || !m_atoms[propName]) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
xcb_atom_t prop = m_atoms[propName]->atom();
|
||
|
if (!prop) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom());
|
||
|
if (!p.b && !p.f && !p.i) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
return &m_props.insert(propName, p).value();
|
||
|
}
|
||
|
|
||
|
bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value)
|
||
|
{
|
||
|
QLatin1String propName(par->prop_name);
|
||
|
PropertyInfo *p = getDevProperty(propName);
|
||
|
if (!p || par->prop_offset >= p->nitems) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
QVariant converted(value);
|
||
|
QVariant::Type convType = QVariant::Int;
|
||
|
if (p->f) {
|
||
|
convType = QVariant::Double;
|
||
|
} else if (value.type() == QVariant::Double) {
|
||
|
converted = QVariant(qRound(static_cast<qreal>(value.toDouble())));
|
||
|
}
|
||
|
|
||
|
if (!converted.convert(convType)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (converted == p->value(par->prop_offset)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (p->b) {
|
||
|
p->b[par->prop_offset] = static_cast<char>(converted.toInt());
|
||
|
} else if (p->i) {
|
||
|
p->i[par->prop_offset] = converted.toInt();
|
||
|
} else if (p->f) {
|
||
|
p->f[par->prop_offset] = converted.toDouble();
|
||
|
}
|
||
|
|
||
|
m_changed.insert(propName);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void XlibTouchpad::setEnabled(bool enable)
|
||
|
{
|
||
|
PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0);
|
||
|
if (enabled.b && *(enabled.b) != enable) {
|
||
|
*(enabled.b) = enable;
|
||
|
enabled.set();
|
||
|
}
|
||
|
|
||
|
flush();
|
||
|
}
|
||
|
|
||
|
bool XlibTouchpad::enabled()
|
||
|
{
|
||
|
PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0);
|
||
|
return enabled.value(0).toBool();
|
||
|
}
|
||
|
|
||
|
const Parameter *XlibTouchpad::findParameter(const QString &name)
|
||
|
{
|
||
|
for (const Parameter *par = m_paramList; par->name; par++) {
|
||
|
if (name == par->name) {
|
||
|
return par;
|
||
|
}
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|