Add some mouse settings

pull/26/head
reionwong 4 years ago
parent 6efdca77fb
commit df06435599

@ -23,6 +23,7 @@ find_package(KF5ModemManagerQt REQUIRED)
pkg_search_module(FontConfig REQUIRED fontconfig IMPORTED_TARGET) pkg_search_module(FontConfig REQUIRED fontconfig IMPORTED_TARGET)
pkg_search_module(ICU REQUIRED icu-i18n) pkg_search_module(ICU REQUIRED icu-i18n)
pkg_check_modules(XORGLIBINPUT xorg-libinput IMPORTED_TARGET)
include_directories(${ICU_INCLUDE_DIRS}) include_directories(${ICU_INCLUDE_DIRS})
@ -44,6 +45,9 @@ set(SRCS
src/powermanager.cpp src/powermanager.cpp
src/cursor/cursorthememodel.cpp src/cursor/cursorthememodel.cpp
src/cursor/cursortheme.cpp src/cursor/cursortheme.cpp
src/cursor/mouse.cpp
src/cursor/inputdummydevice.cpp
src/cursor/libinputsettings.cpp
) )
set(RESOURCES set(RESOURCES
@ -79,6 +83,8 @@ target_link_libraries(${PROJECT_NAME}
X11::X11 X11::X11
X11::Xi X11::Xi
X11::Xcursor X11::Xcursor
PkgConfig::XORGLIBINPUT
) )
file(GLOB TS_FILES translations/*.ts) file(GLOB TS_FILES translations/*.ts)

@ -10,7 +10,7 @@ sudo pacman -S extra-cmake-modules qt5-base qt5-quickcontrols2 freetype2 fontcon
Debian/Ubuntu Dependencies: Debian/Ubuntu Dependencies:
```shell ```shell
sudo apt install cmake debhelper extra-cmake-modules libicu-devlibcrypt-dev libfreetype6-dev libfontconfig1-dev libkf5networkmanagerqt-dev modemmanager-qt-dev qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools qml-module-qtquick-controls2 qml-module-qtquick2 qml-module-qtquick-layouts qml-module-qt-labs-platform qml-module-qt-labs-settings qml-module-qtqml qml-module-qtquick-window2 qml-module-qtquick-shapes qml-module-qtquick-dialogs qml-module-qtquick-particles2 sudo apt install cmake debhelper extra-cmake-modules libicu-devlibcrypt-dev libfreetype6-dev libfontconfig1-dev xserver-xorg-input-libinput-dev libkf5networkmanagerqt-dev modemmanager-qt-dev qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools qml-module-qtquick-controls2 qml-module-qtquick2 qml-module-qtquick-layouts qml-module-qt-labs-platform qml-module-qt-labs-settings qml-module-qtqml qml-module-qtquick-window2 qml-module-qtquick-shapes qml-module-qtquick-dialogs qml-module-qtquick-particles2
``` ```
## Build ## Build

1
debian/control vendored

@ -10,6 +10,7 @@ Build-Depends: cmake,
libfreetype6-dev, libfreetype6-dev,
libfontconfig1-dev, libfontconfig1-dev,
libkf5networkmanagerqt-dev, libkf5networkmanagerqt-dev,
xserver-xorg-input-libinput-dev,
modemmanager-qt-dev, modemmanager-qt-dev,
qtbase5-dev, qtbase5-dev,
libqt5x11extras5-dev, libqt5x11extras5-dev,

@ -18,6 +18,8 @@
#include "powermanager.h" #include "powermanager.h"
#include "cursor/cursorthememodel.h" #include "cursor/cursorthememodel.h"
#include "cursor/mouse.h"
#include "cursor/inputdummydevice.h"
static QObject *passwordSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) static QObject *passwordSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
{ {
@ -67,6 +69,7 @@ Application::Application(int &argc, char **argv)
qmlRegisterType<Language>(uri, 1, 0, "Language"); qmlRegisterType<Language>(uri, 1, 0, "Language");
qmlRegisterType<Fonts>(uri, 1, 0, "Fonts"); qmlRegisterType<Fonts>(uri, 1, 0, "Fonts");
qmlRegisterType<PowerManager>(uri, 1, 0, "PowerManager"); qmlRegisterType<PowerManager>(uri, 1, 0, "PowerManager");
qmlRegisterType<Mouse>(uri, 1, 0, "Mouse");
qmlRegisterSingletonType<Password>(uri, 1, 0, "Password", passwordSingleton); qmlRegisterSingletonType<Password>(uri, 1, 0, "Password", passwordSingleton);
qmlRegisterType<QAbstractItemModel>(); qmlRegisterType<QAbstractItemModel>();

@ -0,0 +1,241 @@
/*
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "inputdummydevice.h"
#include "libinputsettings.h"
#include <QDebug>
#include <libinput-properties.h>
#include <X11/Xatom.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
static Atom s_touchpadAtom;
template<typename Callback>
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) {
XDeviceInfo *dev = info + i;
if ((dev->use == IsXPointer || dev->use == IsXExtensionPointer) && dev->type != s_touchpadAtom) {
callback(dev);
}
}
XFreeDeviceList(info);
}
struct ScopedXDeleter {
static inline void cleanup(void *pointer)
{
if (pointer) {
XFree(pointer);
}
}
};
namespace
{
template<typename T>
void valueWriterPart(T val, Atom valAtom, Display *dpy)
{
Q_UNUSED(val);
Q_UNUSED(valAtom);
Q_UNUSED(dpy);
}
template<>
void valueWriterPart<bool>(bool val, Atom valAtom, Display *dpy)
{
XIForallPointerDevices(dpy, [&](XDeviceInfo *info) {
int deviceid = info->id;
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(dpy, deviceid, valAtom, 0, 1, False, XA_INTEGER, &type_return, &format_return, &num_items_return, &bytes_after_return, &_data);
if (status != Success) {
return;
}
QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data);
_data = nullptr;
if (type_return != XA_INTEGER || !data || format_return != 8) {
return;
}
unsigned char sendVal[2] = {0};
if (num_items_return == 1) {
sendVal[0] = val;
} else {
// Special case for acceleration profile.
const Atom accel = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True);
if (num_items_return != 2 || valAtom != accel) {
return;
}
sendVal[val] = 1;
}
XIChangeProperty(dpy, deviceid, valAtom, XA_INTEGER, 8, XIPropModeReplace, sendVal, num_items_return);
});
}
template<>
void valueWriterPart<qreal>(qreal val, Atom valAtom, Display *dpy)
{
XIForallPointerDevices(dpy, [&](XDeviceInfo *info) {
int deviceid = info->id;
Status status;
Atom float_type = XInternAtom(dpy, "FLOAT", False);
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(dpy, deviceid, valAtom, 0, 1, False, float_type, &type_return, &format_return, &num_items_return, &bytes_after_return, &_data);
if (status != Success) {
return;
}
QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data);
_data = nullptr;
if (type_return != float_type || !data || format_return != 32 || num_items_return != 1) {
return;
}
unsigned char buffer[4096];
float *sendPtr = (float *)buffer;
*sendPtr = val;
XIChangeProperty(dpy, deviceid, valAtom, float_type, format_return, XIPropModeReplace, buffer, 1);
});
}
}
X11LibinputDummyDevice::X11LibinputDummyDevice(QObject *parent, Display *dpy)
: QObject(parent)
, m_settings(new LibinputSettings())
, m_dpy(dpy)
{
m_leftHanded.atom = XInternAtom(dpy, LIBINPUT_PROP_LEFT_HANDED, True);
m_middleEmulation.atom = XInternAtom(dpy, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, True);
m_naturalScroll.atom = XInternAtom(dpy, LIBINPUT_PROP_NATURAL_SCROLL, True);
m_pointerAcceleration.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL, True);
m_pointerAccelerationProfileFlat.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True);
m_supportsDisableEvents.val = false;
m_enabled.val = true;
m_supportedButtons.val = Qt::LeftButton | Qt::MiddleButton | Qt::RightButton;
m_supportsLeftHanded.val = true;
m_supportsMiddleEmulation.val = true;
m_middleEmulationEnabledByDefault.val = false;
m_supportsPointerAcceleration.val = true;
m_defaultPointerAcceleration.val = 0;
m_supportsPointerAccelerationProfileAdaptive.val = true;
m_supportsPointerAccelerationProfileFlat.val = true;
m_defaultPointerAccelerationProfileAdaptive.val = true;
m_defaultPointerAccelerationProfileFlat.val = false;
m_supportsNaturalScroll.val = true;
m_naturalScrollEnabledByDefault.val = false;
s_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True);
// Init
getConfig();
}
X11LibinputDummyDevice::~X11LibinputDummyDevice()
{
delete m_settings;
}
bool X11LibinputDummyDevice::getConfig()
{
auto reset = [this](Prop<bool> &prop, bool defVal) {
prop.reset(m_settings->load(prop.cfgName, defVal));
};
reset(m_leftHanded, false);
reset(m_middleEmulation, false);
reset(m_naturalScroll, false);
reset(m_pointerAccelerationProfileFlat, false);
m_pointerAccelerationProfileAdaptive.reset(!m_settings->load(m_pointerAccelerationProfileFlat.cfgName, false));
m_pointerAcceleration.reset(m_settings->load(m_pointerAcceleration.cfgName, 0.));
emit leftHandedChanged();
emit naturalScrollChanged();
emit pointerAccelerationProfileChanged();
emit pointerAccelerationChanged();
return true;
}
bool X11LibinputDummyDevice::getDefaultConfig()
{
m_leftHanded.set(false);
m_pointerAcceleration.set(m_defaultPointerAcceleration);
m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat);
m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive);
m_middleEmulation.set(m_middleEmulationEnabledByDefault);
m_naturalScroll.set(m_naturalScrollEnabledByDefault);
return true;
}
bool X11LibinputDummyDevice::applyConfig()
{
valueWriter(m_leftHanded);
valueWriter(m_middleEmulation);
valueWriter(m_naturalScroll);
valueWriter(m_pointerAcceleration);
valueWriter(m_pointerAccelerationProfileFlat);
return true;
}
template<typename T>
bool X11LibinputDummyDevice::valueWriter(Prop<T> &prop)
{
// Check atom availability first.
if (prop.atom == None) {
return false;
}
if (prop.val != prop.old) {
m_settings->save(prop.cfgName, prop.val);
}
valueWriterPart(prop.val, prop.atom, m_dpy);
prop.old = prop.val;
return true;
}
bool X11LibinputDummyDevice::isChangedConfig() const
{
return m_leftHanded.changed() || m_pointerAcceleration.changed() || m_pointerAccelerationProfileFlat.changed()
|| m_pointerAccelerationProfileAdaptive.changed() || m_middleEmulation.changed() || m_naturalScroll.changed();
}

@ -0,0 +1,297 @@
/*
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef X11LIBINPUTDUMMYDEVICE_H
#define X11LIBINPUTDUMMYDEVICE_H
#include <QObject>
#include <QString>
#include <QX11Info>
#include <X11/Xdefs.h>
struct LibinputSettings;
class X11LibinputDummyDevice : public QObject
{
Q_OBJECT
//
// general
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(bool supportsDisableEvents READ supportsDisableEvents CONSTANT)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
//
// advanced
Q_PROPERTY(Qt::MouseButtons supportedButtons READ supportedButtons CONSTANT)
Q_PROPERTY(bool supportsLeftHanded READ supportsLeftHanded CONSTANT)
Q_PROPERTY(bool leftHandedEnabledByDefault READ leftHandedEnabledByDefault CONSTANT)
Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged)
Q_PROPERTY(bool supportsMiddleEmulation READ supportsMiddleEmulation CONSTANT)
Q_PROPERTY(bool middleEmulationEnabledByDefault READ middleEmulationEnabledByDefault CONSTANT)
Q_PROPERTY(bool middleEmulation READ isMiddleEmulation WRITE setMiddleEmulation NOTIFY middleEmulationChanged)
//
// acceleration speed and profile
Q_PROPERTY(bool supportsPointerAcceleration READ supportsPointerAcceleration CONSTANT)
Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged)
Q_PROPERTY(bool supportsPointerAccelerationProfileFlat READ supportsPointerAccelerationProfileFlat CONSTANT)
Q_PROPERTY(bool defaultPointerAccelerationProfileFlat READ defaultPointerAccelerationProfileFlat CONSTANT)
Q_PROPERTY(bool pointerAccelerationProfileFlat READ pointerAccelerationProfileFlat WRITE setPointerAccelerationProfileFlat NOTIFY
pointerAccelerationProfileChanged)
Q_PROPERTY(bool supportsPointerAccelerationProfileAdaptive READ supportsPointerAccelerationProfileAdaptive CONSTANT)
Q_PROPERTY(bool defaultPointerAccelerationProfileAdaptive READ defaultPointerAccelerationProfileAdaptive CONSTANT)
Q_PROPERTY(bool pointerAccelerationProfileAdaptive READ pointerAccelerationProfileAdaptive WRITE setPointerAccelerationProfileAdaptive NOTIFY
pointerAccelerationProfileChanged)
//
// scrolling
Q_PROPERTY(bool supportsNaturalScroll READ supportsNaturalScroll CONSTANT)
Q_PROPERTY(bool naturalScrollEnabledByDefault READ naturalScrollEnabledByDefault CONSTANT)
Q_PROPERTY(bool naturalScroll READ isNaturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged)
public:
X11LibinputDummyDevice(QObject *parent, Display *dpy);
~X11LibinputDummyDevice() override;
bool getConfig();
bool getDefaultConfig();
bool applyConfig();
bool isChangedConfig() const;
//
// general
QString name() const
{
return m_name.val;
}
QString sysName() const
{
return m_sysName.val;
}
bool supportsDisableEvents() const
{
return m_supportsDisableEvents.val;
}
void setEnabled(bool enabled)
{
m_enabled.set(enabled);
}
bool isEnabled() const
{
return m_enabled.val;
}
Qt::MouseButtons supportedButtons() const
{
return m_supportedButtons.val;
}
//
// advanced
bool supportsLeftHanded() const
{
return m_supportsLeftHanded.val;
}
bool leftHandedEnabledByDefault() const
{
return m_leftHandedEnabledByDefault.val;
}
bool isLeftHanded() const
{
return m_leftHanded.val;
}
void setLeftHanded(bool set)
{
m_leftHanded.set(set);
}
bool supportsMiddleEmulation() const
{
return m_supportsMiddleEmulation.val;
}
bool middleEmulationEnabledByDefault() const
{
return m_middleEmulationEnabledByDefault.val;
}
bool isMiddleEmulation() const
{
return m_middleEmulation.val;
}
void setMiddleEmulation(bool set)
{
m_middleEmulation.set(set);
}
//
// acceleration speed and profile
bool supportsPointerAcceleration() const
{
return m_supportsPointerAcceleration.val;
}
qreal pointerAcceleration() const
{
return m_pointerAcceleration.val;
}
void setPointerAcceleration(qreal acceleration)
{
m_pointerAcceleration.set(acceleration);
}
bool supportsPointerAccelerationProfileFlat() const
{
return m_supportsPointerAccelerationProfileFlat.val;
}
bool defaultPointerAccelerationProfileFlat() const
{
return m_defaultPointerAccelerationProfileFlat.val;
}
bool pointerAccelerationProfileFlat() const
{
return m_pointerAccelerationProfileFlat.val;
}
void setPointerAccelerationProfileFlat(bool set)
{
m_pointerAccelerationProfileFlat.set(set);
}
bool supportsPointerAccelerationProfileAdaptive() const
{
return m_supportsPointerAccelerationProfileAdaptive.val;
}
bool defaultPointerAccelerationProfileAdaptive() const
{
return m_defaultPointerAccelerationProfileAdaptive.val;
}
bool pointerAccelerationProfileAdaptive() const
{
return m_pointerAccelerationProfileAdaptive.val;
}
void setPointerAccelerationProfileAdaptive(bool set)
{
m_pointerAccelerationProfileAdaptive.set(set);
}
//
// scrolling
bool supportsNaturalScroll() const
{
return m_supportsNaturalScroll.val;
}
bool naturalScrollEnabledByDefault() const
{
return m_naturalScrollEnabledByDefault.val;
}
bool isNaturalScroll() const
{
return m_naturalScroll.val;
}
void setNaturalScroll(bool set)
{
m_naturalScroll.set(set);
}
Q_SIGNALS:
void leftHandedChanged();
void pointerAccelerationChanged();
void pointerAccelerationProfileChanged();
void enabledChanged();
void middleEmulationChanged();
void naturalScrollChanged();
private:
template<typename T>
struct Prop {
explicit Prop(const QString &_name, const QString &_cfgName = "")
: name(_name)
, cfgName(_cfgName)
{
}
void set(T newVal)
{
if (avail && val != newVal) {
val = newVal;
}
}
void set(const Prop<T> &p)
{
if (avail && val != p.val) {
val = p.val;
}
}
bool changed() const
{
return avail && (old != val);
}
void reset(T newVal)
{
val = newVal;
old = newVal;
}
QString name;
QString cfgName;
bool avail = true;
T old;
T val;
Atom atom;
};
template<typename T>
bool valueWriter(Prop<T> &prop);
//
// general
Prop<QString> m_name = Prop<QString>("name");
Prop<QString> m_sysName = Prop<QString>("sysName");
Prop<bool> m_supportsDisableEvents = Prop<bool>("supportsDisableEvents");
Prop<bool> m_enabled = Prop<bool>("enabled");
//
// advanced
Prop<Qt::MouseButtons> m_supportedButtons = Prop<Qt::MouseButtons>("supportedButtons");
Prop<bool> m_supportsLeftHanded = Prop<bool>("supportsLeftHanded");
Prop<bool> m_leftHandedEnabledByDefault = Prop<bool>("leftHandedEnabledByDefault");
Prop<bool> m_leftHanded = Prop<bool>("leftHanded", "XLbInptLeftHanded");
Prop<bool> m_supportsMiddleEmulation = Prop<bool>("supportsMiddleEmulation");
Prop<bool> m_middleEmulationEnabledByDefault = Prop<bool>("middleEmulationEnabledByDefault");
Prop<bool> m_middleEmulation = Prop<bool>("middleEmulation", "XLbInptMiddleEmulation");
//
// acceleration speed and profile
Prop<bool> m_supportsPointerAcceleration = Prop<bool>("supportsPointerAcceleration");
Prop<qreal> m_defaultPointerAcceleration = Prop<qreal>("defaultPointerAcceleration");
Prop<qreal> m_pointerAcceleration = Prop<qreal>("pointerAcceleration", "XLbInptPointerAcceleration");
Prop<bool> m_supportsPointerAccelerationProfileFlat = Prop<bool>("supportsPointerAccelerationProfileFlat");
Prop<bool> m_defaultPointerAccelerationProfileFlat = Prop<bool>("defaultPointerAccelerationProfileFlat");
Prop<bool> m_pointerAccelerationProfileFlat = Prop<bool>("pointerAccelerationProfileFlat", "XLbInptAccelProfileFlat");
Prop<bool> m_supportsPointerAccelerationProfileAdaptive = Prop<bool>("supportsPointerAccelerationProfileAdaptive");
Prop<bool> m_defaultPointerAccelerationProfileAdaptive = Prop<bool>("defaultPointerAccelerationProfileAdaptive");
Prop<bool> m_pointerAccelerationProfileAdaptive = Prop<bool>("pointerAccelerationProfileAdaptive");
//
// scrolling
Prop<bool> m_supportsNaturalScroll = Prop<bool>("supportsNaturalScroll");
Prop<bool> m_naturalScrollEnabledByDefault = Prop<bool>("naturalScrollEnabledByDefault");
Prop<bool> m_naturalScroll = Prop<bool>("naturalScroll", "XLbInptNaturalScroll");
LibinputSettings *m_settings;
Display *m_dpy = nullptr;
};
#endif // X11LIBINPUTDUMMYDEVICE_H

@ -0,0 +1,39 @@
/*
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "libinputsettings.h"
#include <QDebug>
#include <QSettings>
template<>
bool LibinputSettings::load(QString key, bool defVal)
{
QSettings settings("cutefishos", "mouse");
return settings.value(key, defVal).toBool();
}
template<>
qreal LibinputSettings::load(QString key, qreal defVal)
{
QSettings settings("cutefishos", "mouse");
return settings.value(key, defVal).toReal();
}
template<>
void LibinputSettings::save(QString key, bool val)
{
QSettings settings("cutefishos", "mouse");
settings.setValue(key, val);
settings.sync();
}
template<>
void LibinputSettings::save(QString key, qreal val)
{
QSettings settings("cutefishos", "mouse");
settings.setValue(key, val);
settings.sync();
}

@ -0,0 +1,20 @@
/*
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef LIBINPUTSETTINGS_H
#define LIBINPUTSETTINGS_H
#include <QString>
struct LibinputSettings {
template<class T>
T load(QString key, T defVal);
template<class T>
void save(QString key, T val);
};
#endif // LIBINPUTSETTINGS_H

@ -0,0 +1,79 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: Reion Wong <reionwong@gmail.com>
*
* 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 3 of the License, or
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "mouse.h"
Mouse::Mouse(QObject *parent)
: QObject(parent)
, m_inputDummydevice(new X11LibinputDummyDevice(this, QX11Info::display()))
{
connect(m_inputDummydevice, &X11LibinputDummyDevice::leftHandedChanged, this, &Mouse::leftHandedChanged);
connect(m_inputDummydevice, &X11LibinputDummyDevice::pointerAccelerationProfileChanged, this, &Mouse::accelerationChanged);
connect(m_inputDummydevice, &X11LibinputDummyDevice::naturalScrollChanged, this, &Mouse::naturalScrollChanged);
connect(m_inputDummydevice, &X11LibinputDummyDevice::pointerAccelerationChanged, this, &Mouse::pointerAccelerationChanged);
}
Mouse::~Mouse()
{
delete m_inputDummydevice;
}
bool Mouse::leftHanded() const
{
return m_inputDummydevice->isLeftHanded();
}
void Mouse::setLeftHanded(bool enabled)
{
m_inputDummydevice->setLeftHanded(enabled);
m_inputDummydevice->applyConfig();
}
bool Mouse::acceleration() const
{
return m_inputDummydevice->pointerAccelerationProfileFlat();
}
void Mouse::setAcceleration(bool enabled)
{
m_inputDummydevice->setPointerAccelerationProfileFlat(enabled);
m_inputDummydevice->applyConfig();
}
bool Mouse::naturalScroll() const
{
return m_inputDummydevice->isNaturalScroll();
}
void Mouse::setNaturalScroll(bool enabled)
{
m_inputDummydevice->setNaturalScroll(enabled);
m_inputDummydevice->applyConfig();
}
qreal Mouse::pointerAcceleration() const
{
return m_inputDummydevice->pointerAcceleration();
}
void Mouse::setPointerAcceleration(qreal value)
{
m_inputDummydevice->setPointerAcceleration(value);
m_inputDummydevice->applyConfig();
}

@ -0,0 +1,60 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: Reion Wong <reionwong@gmail.com>
*
* 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 3 of the License, or
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOUSE_H
#define MOUSE_H
#include <QObject>
#include "inputdummydevice.h"
class Mouse : public QObject
{
Q_OBJECT
Q_PROPERTY(bool leftHanded READ leftHanded WRITE setLeftHanded NOTIFY leftHandedChanged)
Q_PROPERTY(bool acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
Q_PROPERTY(bool naturalScroll READ naturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged)
Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged)
public:
explicit Mouse(QObject *parent = nullptr);
~Mouse();
bool leftHanded() const;
void setLeftHanded(bool enabled);
bool acceleration() const;
void setAcceleration(bool enabled);
bool naturalScroll() const;
void setNaturalScroll(bool enabled);
qreal pointerAcceleration() const;
void setPointerAcceleration(qreal value);
signals:
void leftHandedChanged();
void accelerationChanged();
void naturalScrollChanged();
void pointerAccelerationChanged();
private:
X11LibinputDummyDevice *m_inputDummydevice;
};
#endif // MOUSE_H

@ -41,15 +41,14 @@ ItemPage {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
// anchors.bottomMargin: FishUI.Units.largeSpacing // anchors.bottomMargin: FishUI.Units.largeSpacing
spacing: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing * 2
Label {
text: qsTr("Theme")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
Label {
text: qsTr("Theme")
color: FishUI.Theme.disabledTextColor
}
// Light Mode and Dark Mode // Light Mode and Dark Mode
RowLayout { RowLayout {
spacing: FishUI.Units.largeSpacing * 2 spacing: FishUI.Units.largeSpacing * 2
@ -69,10 +68,6 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
RowLayout { RowLayout {
spacing: FishUI.Units.largeSpacing spacing: FishUI.Units.largeSpacing
@ -96,17 +91,12 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("Accent color")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
Label {
text: qsTr("Accent color")
color: FishUI.Theme.disabledTextColor
}
GridView { GridView {
id: accentColorView id: accentColorView
height: itemSize height: itemSize

@ -64,7 +64,7 @@ ItemPage {
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
spacing: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing * 2
// Battery Info // Battery Info
BatteryItem { BatteryItem {
@ -118,20 +118,15 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("History")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
visible: history.count > 2 visible: history.count > 2
spacing: 0 spacing: 0
Label {
text: qsTr("History")
color: FishUI.Theme.disabledTextColor
}
HistoryGraph { HistoryGraph {
Layout.fillWidth: true Layout.fillWidth: true
height: 300 height: 300
@ -173,19 +168,14 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("Health")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
visible: battery.capacity visible: battery.capacity
Label {
text: qsTr("Health")
color: FishUI.Theme.disabledTextColor
}
RowLayout { RowLayout {
spacing: FishUI.Units.largeSpacing * 4 spacing: FishUI.Units.largeSpacing * 4
@ -276,10 +266,6 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
RowLayout { RowLayout {
Label { Label {

@ -34,6 +34,14 @@ ItemPage {
id: cursorModel id: cursorModel
} }
Mouse {
id: mouse
}
function syncValues() {
accelerationSlider.init()
}
Scrollable { Scrollable {
anchors.fill: parent anchors.fill: parent
contentHeight: layout.implicitHeight contentHeight: layout.implicitHeight
@ -41,94 +49,179 @@ ItemPage {
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
spacing: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing * 2
Label { RoundedItem {
text: qsTr("Theme") GridLayout {
color: FishUI.Theme.disabledTextColor columns: 2
leftPadding: FishUI.Units.largeSpacing columnSpacing: FishUI.Units.largeSpacing * 1.5
visible: _view.count > 0 rowSpacing: FishUI.Units.largeSpacing * 2
}
Label {
text: qsTr("Left hand")
Layout.fillWidth: true
}
GridView { Switch {
id: _view Layout.fillHeight: true
Layout.fillWidth: true Layout.alignment: Qt.AlignRight
implicitHeight: Math.ceil(_view.count / rowCount) * cellHeight + FishUI.Units.largeSpacing checked: mouse.leftHanded
model: cursorModel rightPadding: 0
interactive: false onCheckedChanged: mouse.leftHanded = checked
visible: _view.count > 0
cellHeight: itemHeight
cellWidth: calcExtraSpacing(itemWidth, _view.width) + itemWidth
currentIndex: cursorModel.themeIndex(cursorModel.currentTheme)
property int rowCount: _view.width / itemWidth
property int itemWidth: 250
property int itemHeight: 170
function calcExtraSpacing(cellSize, containerSize) {
var availableColumns = Math.floor(containerSize / cellSize)
var extraSpacing = 0
if (availableColumns > 0) {
var allColumnSize = availableColumns * cellSize
var extraSpace = Math.max(containerSize - allColumnSize, 0)
extraSpacing = extraSpace / availableColumns
} }
return Math.floor(extraSpacing)
Label {
text: qsTr("Natural scrolling")
}
Switch {
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
checked: mouse.naturalScroll
onCheckedChanged: mouse.naturalScroll = checked
rightPadding: 0
}
// Label {
// text: qsTr("Mouse acceleration")
// }
// Switch {
// Layout.fillHeight: true
// Layout.alignment: Qt.AlignRight
// checked: mouse.acceleration
// onCheckableChanged: mouse.acceleration = checked
// rightPadding: 0
// }
// Label {
// text: qsTr("Disable touchpad when mouse is connected")
// }
// Switch {
// Layout.fillHeight: true
// Layout.alignment: Qt.AlignRight
// rightPadding: 0
// }
} }
}
delegate: Item { RoundedItem {
width: GridView.view.cellWidth RowLayout {
height: GridView.view.cellHeight spacing: FishUI.Units.largeSpacing * 2
scale: _mouseArea.pressed ? 0.95 : 1.0
property bool isCurrent: _view.currentIndex === index Label {
text: qsTr("Speed")
}
Behavior on scale { Slider {
NumberAnimation { id: accelerationSlider
duration: 100 Layout.fillWidth: true
rightPadding: FishUI.Units.largeSpacing
from: 1
to: 11
stepSize: 1
function init() {
accelerationSlider.value = 6 + mouse.pointerAcceleration / 0.2
} }
}
MouseArea { Component.onCompleted: init()
id: _mouseArea
anchors.fill: parent onPressedChanged: {
anchors.margins: FishUI.Units.largeSpacing mouse.pointerAcceleration = Math.round(((value - 6) * 0.2) * 10) / 10
onClicked: {
_view.currentIndex = index
cursorModel.currentTheme = model.id
console.log(model.id)
} }
} }
}
}
Rectangle { RoundedItem {
anchors.fill: parent Label {
anchors.margins: FishUI.Units.largeSpacing text: qsTr("Theme")
color: FishUI.Theme.secondBackgroundColor color: FishUI.Theme.disabledTextColor
radius: FishUI.Theme.mediumRadius visible: _view.count > 0
z: -1 }
border.width: isCurrent ? 3 : 0 GridView {
border.color: FishUI.Theme.highlightColor id: _view
Layout.fillWidth: true
implicitHeight: Math.ceil(_view.count / rowCount) * cellHeight + FishUI.Units.largeSpacing
model: cursorModel
interactive: false
visible: _view.count > 0
cellHeight: itemHeight
cellWidth: calcExtraSpacing(itemWidth, _view.width) + itemWidth
currentIndex: cursorModel.themeIndex(cursorModel.currentTheme)
property int rowCount: _view.width / itemWidth
property int itemWidth: 250
property int itemHeight: 170
function calcExtraSpacing(cellSize, containerSize) {
var availableColumns = Math.floor(containerSize / cellSize)
var extraSpacing = 0
if (availableColumns > 0) {
var allColumnSize = availableColumns * cellSize
var extraSpace = Math.max(containerSize - allColumnSize, 0)
extraSpacing = extraSpace / availableColumns
}
return Math.floor(extraSpacing)
} }
ColumnLayout { delegate: Item {
anchors.fill: parent width: GridView.view.cellWidth
anchors.margins: FishUI.Units.largeSpacing height: GridView.view.cellHeight
scale: _mouseArea.pressed ? 0.95 : 1.0
property bool isCurrent: _view.currentIndex === index
Behavior on scale {
NumberAnimation {
duration: 100
}
}
MouseArea {
id: _mouseArea
anchors.fill: parent
anchors.margins: FishUI.Units.largeSpacing
onClicked: {
_view.currentIndex = index
cursorModel.currentTheme = model.id
console.log(model.id)
}
}
Rectangle {
anchors.fill: parent
anchors.margins: FishUI.Units.largeSpacing + FishUI.Units.smallSpacing
color: FishUI.Theme.darkMode ? "" : "#FAFAFA"
radius: FishUI.Theme.mediumRadius
z: -1
FishUI.IconItem { border.width: isCurrent ? 3 : 0
width: 24 border.color: FishUI.Theme.highlightColor
height: 24
source: model.image
smooth: true
Layout.alignment: Qt.AlignHCenter
} }
Label { ColumnLayout {
text: model.name anchors.fill: parent
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom anchors.margins: FishUI.Units.largeSpacing
bottomPadding: FishUI.Units.largeSpacing
FishUI.IconItem {
width: 24
height: 24
source: model.image
smooth: true
Layout.alignment: Qt.AlignHCenter
}
Label {
text: model.name
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
bottomPadding: FishUI.Units.largeSpacing
}
} }
} }
} }

@ -57,19 +57,18 @@ ItemPage {
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
spacing: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing * 2
Label {
text: qsTr("Brightness")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
visible: brightness.enabled
}
RoundedItem { RoundedItem {
Layout.fillWidth: true Layout.fillWidth: true
visible: brightness.enabled visible: brightness.enabled
Label {
text: qsTr("Brightness")
color: FishUI.Theme.disabledTextColor
visible: brightness.enabled
}
Item { Item {
height: FishUI.Units.smallSpacing / 2 height: FishUI.Units.smallSpacing / 2
} }
@ -109,20 +108,15 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("Screen")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
visible: _screenView.count > 0
}
RoundedItem { RoundedItem {
visible: _screenView.count > 0 visible: _screenView.count > 0
Label {
text: qsTr("Screen")
color: FishUI.Theme.disabledTextColor
visible: _screenView.count > 0
}
ListView { ListView {
id: _screenView id: _screenView
Layout.fillWidth: true Layout.fillWidth: true
@ -280,17 +274,12 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("Scale")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
Label {
text: qsTr("Scale")
color: FishUI.Theme.disabledTextColor
}
TabBar { TabBar {
id: dockSizeTabbar id: dockSizeTabbar
Layout.fillWidth: true Layout.fillWidth: true

@ -38,15 +38,14 @@ ItemPage {
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
spacing: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing * 2
Label {
text: qsTr("Position on screen")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
Label {
text: qsTr("Position on screen")
color: FishUI.Theme.disabledTextColor
}
// Dock // Dock
RowLayout { RowLayout {
spacing: FishUI.Units.largeSpacing * 2 spacing: FishUI.Units.largeSpacing * 2
@ -74,18 +73,13 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("Size")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
// Dock Size // Dock Size
RoundedItem { RoundedItem {
Label {
text: qsTr("Size")
color: FishUI.Theme.disabledTextColor
}
TabBar { TabBar {
id: dockSizeTabbar id: dockSizeTabbar
Layout.fillWidth: true Layout.fillWidth: true
@ -145,18 +139,13 @@ ItemPage {
} }
} }
Item {
height: FishUI.Units.largeSpacing
}
Label {
text: qsTr("Display mode")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
// Visibility // Visibility
RoundedItem { RoundedItem {
Label {
text: qsTr("Display mode")
color: FishUI.Theme.disabledTextColor
}
TabBar { TabBar {
Layout.fillWidth: true Layout.fillWidth: true
currentIndex: appearance.dockVisibility currentIndex: appearance.dockVisibility

@ -86,7 +86,7 @@ ItemPage {
columns: 2 columns: 2
columnSpacing: FishUI.Units.largeSpacing * 1.5 columnSpacing: FishUI.Units.largeSpacing * 1.5
rowSpacing: FishUI.Units.largeSpacing rowSpacing: FishUI.Units.largeSpacing * 2
Label { Label {
text: qsTr("General Font") text: qsTr("General Font")

@ -41,15 +41,14 @@ ItemPage {
ColumnLayout { ColumnLayout {
id: layout id: layout
anchors.fill: parent anchors.fill: parent
spacing: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing * 2
Label {
text: qsTr("Mode")
color: FishUI.Theme.disabledTextColor
leftPadding: FishUI.Units.largeSpacing
}
RoundedItem { RoundedItem {
Label {
text: qsTr("Mode")
color: FishUI.Theme.disabledTextColor
}
RowLayout { RowLayout {
spacing: FishUI.Units.largeSpacing * 2 spacing: FishUI.Units.largeSpacing * 2

@ -26,6 +26,7 @@ Rectangle {
default property alias content : _mainLayout.data default property alias content : _mainLayout.data
property alias spacing: _mainLayout.spacing property alias spacing: _mainLayout.spacing
property alias layout: _mainLayout
color: FishUI.Theme.secondBackgroundColor color: FishUI.Theme.secondBackgroundColor
radius: FishUI.Theme.mediumRadius radius: FishUI.Theme.mediumRadius
@ -41,5 +42,6 @@ Rectangle {
anchors.rightMargin: FishUI.Units.largeSpacing anchors.rightMargin: FishUI.Units.largeSpacing
anchors.topMargin: FishUI.Units.largeSpacing anchors.topMargin: FishUI.Units.largeSpacing
anchors.bottomMargin: FishUI.Units.largeSpacing anchors.bottomMargin: FishUI.Units.largeSpacing
spacing: FishUI.Units.largeSpacing
} }
} }

@ -101,15 +101,6 @@ Item {
category: qsTr("Display and appearance") category: qsTr("Display and appearance")
} }
ListElement {
title: qsTr("Mouse")
name: "cursor"
page: "qrc:/qml/Cursor/Main.qml"
iconSource: "cursor.svg"
iconColor: "#0D9BF1"
category: qsTr("Display and appearance")
}
ListElement { ListElement {
title: qsTr("Fonts") title: qsTr("Fonts")
name: "fonts" name: "fonts"
@ -146,6 +137,15 @@ Item {
category: qsTr("System") category: qsTr("System")
} }
ListElement {
title: qsTr("Mouse")
name: "cursor"
page: "qrc:/qml/Cursor/Main.qml"
iconSource: "cursor.svg"
iconColor: "#0D9BF1"
category: qsTr("System")
}
// ListElement { // ListElement {
// title: qsTr("Application") // title: qsTr("Application")
// name: "application" // name: "application"

Loading…
Cancel
Save