File indexing completed on 2024-06-16 05:09:02

0001 /*
0002     SPDX-FileCopyrightText: 2017 Roman Gilg <subdiff@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "touchpadconfig.h"
0008 
0009 #include "../logging.h"
0010 #include "touchpadbackend.h"
0011 #include <config-build-options.h>
0012 
0013 #include <KLocalizedContext>
0014 #include <KLocalizedString>
0015 #include <KPluginFactory>
0016 #include <KWindowSystem>
0017 
0018 #include <QQmlContext>
0019 #include <QQmlEngine>
0020 #include <QQmlProperty>
0021 #include <QQuickItem>
0022 #include <QVBoxLayout>
0023 
0024 K_PLUGIN_CLASS_WITH_JSON(TouchpadConfig, "kcm_touchpad.json")
0025 
0026 extern "C" {
0027 Q_DECL_EXPORT void kcminit()
0028 {
0029 #if BUILD_KCM_TOUCHPAD_X11
0030     if (KWindowSystem::isPlatformX11()) {
0031         TouchpadConfig::kcmInit();
0032     }
0033 #endif
0034 }
0035 }
0036 
0037 TouchpadConfig::TouchpadConfig(QObject *parent, const KPluginMetaData &data)
0038     : KCModule(parent, data)
0039 {
0040     m_backend = TouchpadBackend::implementation();
0041 
0042     m_initError = !m_backend->errorString().isNull();
0043 
0044     m_view = new QQuickWidget(widget());
0045 
0046     QVBoxLayout *layout = new QVBoxLayout(widget());
0047 
0048     layout->addWidget(m_view);
0049     widget()->setLayout(layout);
0050 
0051     m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
0052     m_view->setClearColor(Qt::transparent);
0053     m_view->setAttribute(Qt::WA_AlwaysStackOnTop);
0054 
0055     m_view->rootContext()->setContextProperty("backend", m_backend);
0056     m_view->rootContext()->setContextProperty("deviceModel", QVariant::fromValue(m_backend->getDevices().toList()));
0057 
0058     QObject::connect(m_view, &QQuickWidget::statusChanged, [&](QQuickWidget::Status status) {
0059         if (status == QQuickWidget::Ready) {
0060             connect(m_view->rootObject(), SIGNAL(changeSignal()), this, SLOT(onChange()));
0061         }
0062     });
0063 
0064     qmlRegisterSingletonInstance("org.kde.touchpad.kcm", 1, 0, "TouchpadConfig", this);
0065 
0066     m_view->engine()->rootContext()->setContextObject(new KLocalizedContext(m_view->engine()));
0067     m_view->setSource(QUrl("qrc:/libinput/touchpad.qml"));
0068     m_view->resize(QSize(500, 600));
0069 
0070     if (m_initError) {
0071         Q_EMIT showMessage(m_backend->errorString());
0072     } else {
0073         connect(m_backend, &TouchpadBackend::touchpadAdded, this, &TouchpadConfig::onTouchpadAdded);
0074         connect(m_backend, &TouchpadBackend::touchpadRemoved, this, &TouchpadConfig::onTouchpadRemoved);
0075     }
0076 
0077     setButtons(KCModule::Default | KCModule::Apply);
0078 }
0079 
0080 void TouchpadConfig::kcmInit()
0081 {
0082 #if BUILD_KCM_TOUCHPAD_X11
0083     TouchpadBackend *backend = TouchpadBackend::implementation();
0084     if (backend->getMode() == TouchpadInputBackendMode::XLibinput) {
0085         backend->getConfig();
0086         backend->applyConfig();
0087     }
0088 #endif
0089 }
0090 
0091 void TouchpadConfig::load()
0092 {
0093     // in case of critical init error in backend, don't try
0094     if (m_initError) {
0095         return;
0096     }
0097 
0098     if (!m_backend->getConfig()) {
0099         Q_EMIT showMessage(i18n("Error while loading values. See logs for more information. Please restart this configuration module."));
0100     } else {
0101         if (!m_backend->touchpadCount()) {
0102             Q_EMIT showMessage(i18n("No touchpad found. Connect touchpad now."));
0103         }
0104     }
0105     QMetaObject::invokeMethod(m_view->rootObject(), "syncValuesFromBackend");
0106 }
0107 
0108 void TouchpadConfig::save()
0109 {
0110     if (!m_backend->applyConfig()) {
0111         Q_EMIT showMessage(i18n("Not able to save all changes. See logs for more information. Please restart this configuration module and try again."));
0112     } else {
0113         Q_EMIT showMessage(QString());
0114     }
0115 
0116     // load newly written values
0117     load();
0118     // in case of error, config still in changed state
0119     setNeedsSave(m_backend->isChangedConfig());
0120 }
0121 
0122 void TouchpadConfig::defaults()
0123 {
0124     // in case of critical init error in backend, don't try
0125     if (m_initError) {
0126         return;
0127     }
0128 
0129     if (!m_backend->getDefaultConfig()) {
0130         Q_EMIT showMessage(i18n("Error while loading default values. Failed to set some options to their default values."));
0131     }
0132     QMetaObject::invokeMethod(m_view->rootObject(), "syncValuesFromBackend");
0133     setNeedsSave(m_backend->isChangedConfig());
0134 }
0135 
0136 void TouchpadConfig::onChange()
0137 {
0138     if (!m_backend->touchpadCount()) {
0139         return;
0140     }
0141     hideErrorMessage();
0142     setNeedsSave(m_backend->isChangedConfig());
0143 }
0144 
0145 void TouchpadConfig::onTouchpadAdded(bool success)
0146 {
0147     QQuickItem *rootObj = m_view->rootObject();
0148 
0149     if (!success) {
0150         Q_EMIT showMessage(i18n("Error while adding newly connected device. Please reconnect it and restart this configuration module."));
0151     }
0152 
0153     int activeIndex;
0154     if (m_backend->touchpadCount() == 1) {
0155         // if no touchpad was connected previously, show the new device and hide the no-device-message
0156         activeIndex = 0;
0157         hideErrorMessage();
0158     } else {
0159         activeIndex = QQmlProperty::read(rootObj, "deviceIndex").toInt();
0160     }
0161     m_view->rootContext()->setContextProperty("deviceModel", QVariant::fromValue(m_backend->getDevices()));
0162     QMetaObject::invokeMethod(rootObj, "resetModel", Q_ARG(QVariant, activeIndex));
0163     QMetaObject::invokeMethod(rootObj, "syncValuesFromBackend");
0164 }
0165 
0166 void TouchpadConfig::onTouchpadRemoved(int index)
0167 {
0168     QQuickItem *rootObj = m_view->rootObject();
0169 
0170     int activeIndex = QQmlProperty::read(rootObj, "deviceIndex").toInt();
0171     if (activeIndex == index) {
0172         if (m_backend->touchpadCount()) {
0173             Q_EMIT showMessage(i18n("Touchpad disconnected. Closed its setting dialog."), 0 /*Kirigami.MessageType.Information*/);
0174         } else {
0175             Q_EMIT showMessage(i18n("Touchpad disconnected. No other touchpads found."), 0 /*Kirigami.MessageType.Information*/);
0176         }
0177         activeIndex = 0;
0178     } else {
0179         if (index < activeIndex) {
0180             activeIndex--;
0181         }
0182     }
0183     m_view->rootContext()->setContextProperty("deviceModel", QVariant::fromValue(m_backend->getDevices()));
0184     QMetaObject::invokeMethod(m_view->rootObject(), "resetModel", Q_ARG(QVariant, activeIndex));
0185     QMetaObject::invokeMethod(rootObj, "syncValuesFromBackend");
0186 
0187     setNeedsSave(m_backend->isChangedConfig());
0188 }
0189 
0190 void TouchpadConfig::hideErrorMessage()
0191 {
0192     Q_EMIT showMessage(QString());
0193 }
0194 
0195 #include "touchpadconfig.moc"