Logo Search packages:      
Sourcecode: synaptiks version File versions  Download package

synaptiksdaemon.cpp

/*
 * synaptiks -- a touchpad control tool
 *
 *
 * Copyright (C) 2010 Sebastian Wiesner <basti.wiesner@gmx.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "config-synaptiks.h"
#include "synaptiksdaemon.h"
#include "synaptiksadaptor.h"
#include "synaptiksconfiguration.h"
#include "touchpadmanager.h"
#include "mousedevicesmonitor.h"
#include "keyboardmonitor.h"
#include "touchpad.h"
#include <KDebug>
#include <KPluginFactory>
#include <KAboutData>
#include <KNotification>
#include <KLocale>
#include <KLocalizedString>
#include <KIconLoader>
#include <KActionCollection>
#include <KToggleAction>
#include <QtCore/QPointer>


using namespace synaptiks;

K_PLUGIN_FACTORY(SynaptiksFactory, registerPlugin<SynaptiksDaemon>();)
K_EXPORT_PLUGIN(SynaptiksFactory("synaptiksdaemon"))


inline QString switchMessage(bool on, const QString reason,
                             const QVariant &closure) {
    QString message;
    if (reason == "keyboard") {
        message = on? i18nc("@info daemon notification message detail",
                             "User stopped typing"):
                  i18nc("@info daemon notification message detail",
                        "User started typing");
    } else if (reason == "mouse") {
        message = on? i18nc("@info daemon notification message detail",
                            "<resource>%1</resource> unplugged",
                            closure.toString()):
                  i18nc("@info daemon notification message detail",
                        "<resource>%1</resource> plugged",
                        closure.toString());
    }
    return on? i18nc("@info daemon notification message",
                     "Touchpad switched on.<nl/>%1", message):
        i18nc("@info daemon notification message",
              "Touchpad switched off.<nl />%1", message);
}


namespace synaptiks {
00080     class SynaptiksDaemonPrivate {
    public:
        QPointer<TouchpadManager> touchpadManager;
        synaptiks::SynaptiksConfiguration *config;
        KComponentData applicationData;
        KIconLoader *iconLoader;
        KActionCollection *globalActions;
    };
}


00091 SynaptiksDaemon::SynaptiksDaemon(QObject *parent, const QList<QVariant>&):
    KDEDModule(parent), d_ptr(new SynaptiksDaemonPrivate) {
    Q_D(SynaptiksDaemon);

    KGlobal::locale()->insertCatalog("synaptiks");

    KAboutData about("synaptiks", 0, ki18n("synaptiks"), SYNAPTIKS_VERSION,
                     ki18n("A touchpad control daemon"),
                     KAboutData::License_BSD,
                     ki18n("Copyright © 2009, 2010 Sebastian Wiesner"),
                     KLocalizedString(),
                     "http://synaptiks.lunaryorn.de/");
    about.setTranslator(ki18nc("NAME OF TRANSLATORS", "Your names"),
                        ki18nc("EMAIL OF TRANSLATORS", "Your emails"));
    about.addAuthor(ki18n("Sebastian Wiesner"), ki18n("Programmer"),
                    "basti.wiesner@gmx.net");
    d->applicationData = KComponentData(about);
    d->iconLoader = new KIconLoader(d->applicationData);

    d->config = new SynaptiksConfiguration();
    d->touchpadManager = 0;

    Touchpad *touchpad = Touchpad::findTouchpad(this);
    MouseDevicesMonitor *monitor = new MouseDevicesMonitor(this);

    QDBusConnection::sessionBus().registerObject(
        "/MouseDevicesMonitor", monitor,
        QDBusConnection::ExportScriptableContents);

    if (!touchpad) {
        if (!Touchpad::isSupported()) {
            this->notifyError(
                i18nc("@info daemon error notification",
                      "<warning>The system does not support touchpad "
                      "configuration.</warning>"));
        } else {
            this->notifyError(
                i18nc("@info daemon notification error",
                      "<warning>No configurable touchpad was "
                      "found.</warning>"));
        }
    } else {
        // create the touchpad manager
        d->touchpadManager = new TouchpadManager(touchpad, monitor, this);
        this->connect(d->touchpadManager,
                      SIGNAL(touchpadSwitched(bool, const QString&,
                                              const QVariant&)),
                      SLOT(showTouchpadState(bool, const QString&,
                                             const QVariant&)));
        this->connect(d->touchpadManager,
                      SIGNAL(touchpadError(const QString&)),
                      SLOT(notifyError(const QString&)));


        // dump settings from touchpad driver to configuration and write the
        // settings to a file to make them available to the kcmodule
        this->dumpTouchpadToConfiguration();
        d->config->setSharedConfig(KSharedConfig::openConfig(
                                       "synaptiksrc-defaults"));
        d->config->writeConfig();
        // update all defaults in the configuration scheme ...
        foreach (KConfigSkeletonItem *item, d->config->items()) {
            item->swapDefault();
        }
        // ... and finally read the actual configuration
        d->config->setSharedConfig(
            KSharedConfig::openConfig("synaptiksrc"));
        d->config->readConfig();

        // action to switch the touchpad with global shortcut
        d->globalActions = new KActionCollection(this, d->applicationData);
        KAction *touchpadOn = new KToggleAction(
            i18nc("@action:button hidden action", "Touchpad on"),
            d->globalActions);
        d->globalActions->addAction("touchpadOn", touchpadOn);
        touchpadOn->setGlobalShortcut(
            KShortcut(i18nc("touchpadOn shortcut", "Ctrl+Alt+T")));
        this->connect(touchpadOn, SIGNAL(triggered(bool)),
                      SLOT(touchpadOnTriggered(bool)));

        // initial touchpad state
        int state = d->config->touchpadStateAtStartup();
        if (state != SynaptiksConfiguration::UnchangedState) {
            touchpad->setOn(state == SynaptiksConfiguration::OnState);
        }
        // and the rest of the configuration
        this->reparseConfiguration();

        // register on session bus
        QDBusConnection::sessionBus().registerObject("/Touchpad", touchpad);
        QDBusConnection::sessionBus().registerObject(
            "/TouchpadManager", d->touchpadManager,
            QDBusConnection::ExportScriptableContents);
    }

    new SynaptiksAdaptor(this);
    QDBusConnection::sessionBus().registerService("org.kde.synaptiks");
}

00190 SynaptiksDaemon::~SynaptiksDaemon() {
    delete this->d_ptr->config;
    delete this->d_ptr;
}

00195 void SynaptiksDaemon::showTouchpadState() const {
    Q_D(const SynaptiksDaemon);
    this->showTouchpadState(
        d->touchpadManager->touchpad()->isOn(), QString());
}

00201 void SynaptiksDaemon::showTouchpadState(
    bool on, const QString &reason, const QVariant &closure) const {
    Q_D(const SynaptiksDaemon);
    // otherwise update the gui state
    int state;
    QString event, iconName;
    QString text = switchMessage(on, reason, closure);
    kDebug() << "touchpad switched" << (on ? "on" : "off");

    if (on) {
        event = "touchpadOn";
        iconName = "touchpad-on";
        state = KIconLoader::ActiveState;
    } else {
        event = "touchpadOff";
        iconName = "touchpad-off";
        state = KIconLoader::DisabledState;
    }
    QAction *action = d->globalActions->action("touchpadOn");
    Q_ASSERT(action);
    action->setChecked(on);
    KNotification *notification = new KNotification(event);
    notification->setText(text);
    notification->addContext(
        "reason", reason != "interactive"? reason: QString());
    notification->setPixmap(
        d->iconLoader->loadIcon(iconName, KIconLoader::Panel));
    notification->setComponentData(d->applicationData);
    notification->sendEvent();
}

00232 void SynaptiksDaemon::reparseConfiguration() {
    Q_D(SynaptiksDaemon);
    d->config->readConfig();

    d->touchpadManager->setMonitorKeyboard(
        d->config->switchOffOnKeyboardActivity());

    if (d->touchpadManager->monitorKeyboard()) {
        KeyboardMonitor *m = d->touchpadManager->keyboardMonitor();
        m->setProperty("ignoreKeys",
                       d->config->findItem("KeysToIgnore")->property());
        // sub-millisecond fractions are thrown away by implicit cast to int
        m->setIdleTime(d->config->idleTime()*1000);
    }

    d->touchpadManager->setIgnoredMouseDevices(
        d->config->ignoredMouseDevices());
    d->touchpadManager->setMonitorMouseDevices(
        d->config->switchOffIfMouseIsPlugged());

    // apply touchpad configuration.  First all items, that directly map to
    // touchpad properties ...
    QList<QString> names;
    names
        // general configuration
        << "CircularTouchpad"
        // motion configuration
        << "MinimumSpeed" << "MaximumSpeed" << "AccelerationFactor"
        << "EdgeMotionAlways"
        // scrolling configuration
        << "CircularScrolling" << "CircularScrollingTrigger"
        << "HorizontalTwoFingerScrolling" << "VerticalTwoFingerScrolling"
        << "HorizontalEdgeScrolling" << "VerticalEdgeScrolling"
        << "HorizontalScrollingDistance" << "VerticalScrollingDistance"
        << "CornerCoasting"
        // tapping configuration
        << "FastTaps" << "TapAndDragGesture" << "LockedDrags";
    foreach (const QString &name, names) {
        KConfigSkeletonItem *item = d->config->findItem(name);
        Q_ASSERT(item);
        QString property = name;
        property[0] = property.at(0).toLower();
        this->setTouchpadProperty(property.toAscii(), item->property());
    }

    // ... and finally the more complicated stuff
    if (d->config->coasting()) {
        this->setTouchpadProperty(
            "coastingSpeed", d->config->coastingSpeed());
    } else {
        // 0.0 for coasting speed disables coasting
        this->setTouchpadProperty("coastingSpeed", 0.0);
    }
    // circular scrolling distance in degrees must be converted to radians
    double radians = (d->config->circularScrollingDistance()*M_PI)/180.0;
    this->setTouchpadProperty("circularScrollingDistance", radians);
    // LockedDragsTimeout scaled to milliseconds
    this->setTouchpadProperty("lockedDragsTimeout",
                              d->config->lockedDragsTimeout() * 1000);
    // corner and finger button settings composed from single items
    QByteArray buttons;
    for (int i=0; i < 4; i++) {
        buttons.append(d->config->cornerButton(i));
    }
    this->setTouchpadProperty("cornerButtons", buttons);
    buttons.clear();
    for (int i=0; i < 3; i++) {
        buttons.append(d->config->fingerButton(i));
    }
    this->setTouchpadProperty("fingerButtons", buttons);
}

00304 void SynaptiksDaemon::dumpTouchpadToConfiguration() {
    Q_D(SynaptiksDaemon);
    // First all items, that directly map to touchpad properties ...
    QList<QString> names;
    names
        // general configuration
        << "CircularTouchpad"
        // motion configuration
        << "MinimumSpeed" << "MaximumSpeed" << "AccelerationFactor"
        << "EdgeMotionAlways"
        // scrolling configuration
        << "CircularScrolling" << "CircularScrollingTrigger"
        << "HorizontalTwoFingerScrolling" << "VerticalTwoFingerScrolling"
        << "HorizontalEdgeScrolling" << "VerticalEdgeScrolling"
        << "HorizontalScrollingDistance" << "VerticalScrollingDistance"
        << "CornerCoasting" << "CoastingSpeed"
        // tapping configuration
        << "FastTaps" << "TapAndDragGesture" << "LockedDrags";
    foreach (const QString &name, names) {
        KConfigSkeletonItem *item = d->config->findItem(name);
        Q_ASSERT(item);
        QString property = name;
        property[0] = property.at(0).toLower();
        QVariant value = this->touchpadProperty(property.toAscii());
        if (value.userType() == QMetaType::Float) {
            value = round(value.toFloat()*100)/100.0;
            kDebug() << "rounding" << name << "to" << value;
        }
        kDebug() << "setting" << name << "to" << value;
        item->setProperty(value);
    }

    // ... and the more complicated stuff
    float coastingSpeed = this->touchpadProperty("coastingSpeed").toFloat();
    d->config->setCoasting(coastingSpeed != 0.0);
    // convert to degrees
    float circScrollDistance =
        this->touchpadProperty("circularScrollingDistance").toFloat();
    d->config->setCircularScrollingDistance(
        round(circScrollDistance*180/M_PI));
    // lockedDragsTimeout scaled to seconds
    int lockedDragsTimeout =
        this->touchpadProperty("lockedDragsTimeout").toInt();
    d->config->setLockedDragsTimeout(lockedDragsTimeout / 1000.0);
    // corner and finger buttons
    QByteArray buttons;
    buttons = this->touchpadProperty("cornerButtons").toByteArray();
    for (int i=0; i < 4; i++) {
        d->config->setCornerButton(i, buttons.at(i));
    }
    buttons = this->touchpadProperty("fingerButtons").toByteArray();
    for (int i=0; i < 3; i++) {
        d->config->setFingerButton(i, buttons.at(i));
    }
}

00360 bool SynaptiksDaemon::isTouchpadAvailable() const {
    Q_D(const SynaptiksDaemon);
    // if touchpad manager is a null pointer, no touchpad is available.
    return d->touchpadManager;
}

00366 QString SynaptiksDaemon::touchpadNotAvailableMessage() const {
    if (!Touchpad::isSupported()) {
        return i18nc(
            "@info connectivity error",
            "<warning>Touchpad configuration is not supported on this "
            "system.</warning>"
            "The <application>synaptics</application> driver "
            "is either not loaded or too old.  Refer to the "
            "documentation for information about the required driver "
            "version.");
    } else {
        return i18nc(
            "@info connectivity error",
            "<warning>No configurable touchpad was found on your "
            "system.</warning>"
            "If your system has a physical touchpad, please make "
            "sure, that it is handled by the "
            "<application>synaptics</application> driver.");
    }
}


00388 void SynaptiksDaemon::setTouchpadProperty(const char *name,
                                          const QVariant &value) {
    Q_D(SynaptiksDaemon);
    try {
        d->touchpadManager->touchpad()->setProperty(name, value);
    } catch (const QXDeviceError &error) {
        this->notifyError(error.toString());
    }
}

00398 QVariant SynaptiksDaemon::touchpadProperty(const char *name) const {
    Q_D(const SynaptiksDaemon);
    try {
        return d->touchpadManager->touchpad()->property(name);
    } catch (const QXDeviceError &error) {
        return QVariant();
    }
}

00407 void SynaptiksDaemon::notifyError(const QString &message) const {
    Q_D(const SynaptiksDaemon);
    KNotification *notification = new KNotification("touchpadError");
    notification->setTitle(
        i18nc("@title daemon error notification", "Touchpad error"));
    notification->setText(message);
    notification->setPixmap(
        d->iconLoader->loadIcon("touchpad-unavailable",
                                KIconLoader::Panel));
    notification->setComponentData(d->applicationData);
    notification->sendEvent();
}

00420 void SynaptiksDaemon::touchpadOnTriggered(bool on) const {
    Q_D(const SynaptiksDaemon);
    d->touchpadManager->setTouchpadOn(on, "interactive");
}

#include "moc_synaptiksdaemon.cpp"

Generated by  Doxygen 1.6.0   Back to index