Commit 073b1990 authored by Àlex Fiestas's avatar Àlex Fiestas

Adding the base for udev support

parent 46490474
......@@ -21,6 +21,7 @@ include(KDE4Defaults)
option(WITH_XINERAMA "Xinerama support for multi-headed X displays" ON)
find_package(Strigi)
find_package(UDev)
set_package_properties(Strigi PROPERTIES DESCRIPTION "Desktop indexing and search support"
URL "http://strigi.sourceforge.net"
TYPE REQUIRED
......
......@@ -13,6 +13,8 @@ set(powerdevilupowerbackend_SRCS
backends/upower/powerdevilupowerbackend.cpp
backends/upower/xrandrbrightness.cpp
backends/upower/xrandrx11helper.cpp
backends/upower/udevqtclient.cpp
backends/upower/udevqtdevice.cpp
)
set_source_files_properties(
......
......@@ -72,6 +72,7 @@ kde4_add_plugin(kded_powerdevil ${kded_powerdevil_SRCS} ${POWERDEVIL_BACKEND_SRC
target_link_libraries(kded_powerdevil
${KDE4_KDECORE_LIBS}
${POWERDEVIL_BACKEND_LIBS}
${UDEV_LIBS}
powerdevilcore
)
......
......@@ -33,6 +33,7 @@
#include "xrandrbrightness.h"
#include "upowersuspendjob.h"
#include "login1suspendjob.h"
#include "udevqt.h"
#define HELPER_ID "org.kde.powerdevil.backlighthelper"
......@@ -115,6 +116,9 @@ void PowerDevilUPowerBackend::init()
m_kbdBacklight = new OrgFreedesktopUPowerKbdBacklightInterface(UPOWER_SERVICE, "/org/freedesktop/UPower/KbdBacklight", QDBusConnection::systemBus(), this);
m_brightnessControl = new XRandrBrightness();
m_randrHelper = new XRandRX11Helper();
UdevQt::Client *client = new UdevQt::Client(QStringList("backlight"), this);
connect(client, SIGNAL(deviceChanged(UdevQt::Device)), SLOT(deviceChanged(UdevQt::Device)));
connect(m_randrHelper, SIGNAL(brightnessChanged()), this, SLOT(slotScreenBrightnessChanged()));
// Capabilities
......@@ -199,6 +203,19 @@ void PowerDevilUPowerBackend::init()
setBackendIsReady(controls, supported);
}
void PowerDevilUPowerBackend::deviceChanged(const UdevQt::Device &device)
{
qDebug() << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
qDebug() << "Path:" << device.sysfsPath();
qDebug() << "Properties:" << device.deviceProperties();
Q_FOREACH (const QString &key, device.deviceProperties()) {
qDebug() << "\t" << key << ":" << device.deviceProperty(key).toString();
}
qDebug() << "Driver:" << device.driver();
qDebug() << "Subsystem:" << device.subsystem();
qDebug() << "\t" << "brightness" << ":" << device.sysfsProperty("brightness").toString();
}
void PowerDevilUPowerBackend::brightnessKeyPressed(PowerDevil::BackendInterface::BrightnessKeyType type, BrightnessControlType controlType)
{
BrightnessControlsList allControls = brightnessControlsAvailable();
......
......@@ -32,10 +32,12 @@
#include "upower_device_interface.h"
#include "upower_interface.h"
#include "upower_kbdbacklight_interface.h"
#include "udevqt.h"
#define UPOWER_SERVICE "org.freedesktop.UPower"
#define LOGIN1_SERVICE "org.freedesktop.login1"
class UdevHelper;
class XRandRX11Helper;
class XRandrBrightness;
......@@ -67,6 +69,7 @@ private slots:
void slotPropertyChanged();
void slotLogin1Resuming(bool active);
void slotScreenBrightnessChanged();
void deviceChanged(const UdevQt::Device &device);
private:
// upower devices
......@@ -76,6 +79,7 @@ private:
QMap<BrightnessControlType, float> m_cachedBrightnessMap;
XRandrBrightness *m_brightnessControl;
XRandRX11Helper *m_randrHelper;
OrgFreedesktopUPowerInterface *m_upowerInterface;
OrgFreedesktopUPowerKbdBacklightInterface *m_kbdBacklight;
......
/*
Copyright 2009 Benjamin K. Stuhl <bks24@cornell.edu>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDEVQT_H
#define UDEVQT_H
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
namespace UdevQt
{
class DevicePrivate;
class Device
{
public:
Device();
Device(const Device &other);
~Device();
Device &operator= (const Device &other);
bool isValid() const;
QString subsystem() const;
QString devType() const;
QString name() const;
QString sysfsPath() const;
int sysfsNumber() const;
QString driver() const;
QString primaryDeviceFile() const;
QStringList alternateDeviceSymlinks() const;
QStringList deviceProperties() const;
QStringList sysfsProperties() const;
Device parent() const;
// ### should this really be a QVariant? as far as udev knows, everything is a string...
// see also Client::devicesByProperty
QVariant deviceProperty(const QString &name) const;
QString decodedDeviceProperty(const QString &name) const;
QVariant sysfsProperty(const QString &name) const;
Device ancestorOfType(const QString &subsys, const QString &devtype) const;
private:
Device(DevicePrivate *devPrivate);
friend class Client;
friend class ClientPrivate;
DevicePrivate *d;
};
typedef QList<Device> DeviceList;
class ClientPrivate;
class Client : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList watchedSubsystems READ watchedSubsystems WRITE setWatchedSubsystems)
public:
Client(QObject *parent = 0);
Client(const QStringList &subsystemList, QObject *parent = 0);
~Client();
QStringList watchedSubsystems() const;
void setWatchedSubsystems(const QStringList &subsystemList);
DeviceList allDevices();
DeviceList devicesByProperty(const QString &property, const QVariant &value);
DeviceList devicesBySubsystem(const QString &subsystem);
Device deviceByDeviceFile(const QString &deviceFile);
Device deviceBySysfsPath(const QString &sysfsPath);
Device deviceBySubsystemAndName(const QString &subsystem, const QString &name);
signals:
void deviceAdded(const UdevQt::Device &dev);
void deviceRemoved(const UdevQt::Device &dev);
void deviceChanged(const UdevQt::Device &dev);
void deviceOnlined(const UdevQt::Device &dev);
void deviceOfflined(const UdevQt::Device &dev);
private:
friend class ClientPrivate;
Q_PRIVATE_SLOT(d, void _uq_monitorReadyRead(int fd))
ClientPrivate *d;
};
}
#endif
/*
Copyright 2009 Benjamin K. Stuhl <bks24@cornell.edu>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UDEVQT_P_H
#define UDEVQT_P_H
extern "C"
{
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
#include <libudev.h>
}
class QByteArray;
class QSocketNotifier;
namespace UdevQt
{
class DevicePrivate
{
public:
DevicePrivate(struct udev_device *udev_, bool ref = true);
~DevicePrivate();
DevicePrivate &operator=(const DevicePrivate& other);
QString decodePropertyValue(const QByteArray &encoded) const;
struct udev_device *udev;
};
class ClientPrivate
{
public:
enum ListenToWhat { ListenToList, ListenToNone };
ClientPrivate(Client *q_);
~ClientPrivate();
void init(const QStringList &subsystemList, ListenToWhat what);
void setWatchedSubsystems(const QStringList &subsystemList);
void _uq_monitorReadyRead(int fd);
DeviceList deviceListFromEnumerate(struct udev_enumerate *en);
struct udev *udev;
struct udev_monitor *monitor;
Client *q;
QSocketNotifier *monitorNotifier;
QStringList watchedSubsystems;
};
inline QStringList listFromListEntry(struct udev_list_entry *list)
{
QStringList ret;
struct udev_list_entry *entry;
udev_list_entry_foreach(entry, list) {
ret << QString::fromLatin1(udev_list_entry_get_name(entry));
}
return ret;
}
}
#endif
/*
Copyright 2009 Benjamin K. Stuhl <bks24@cornell.edu>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "udevqt.h"
#include "udevqt_p.h"
#include <sys/stat.h>
#include <QtCore/QSocketNotifier>
namespace UdevQt {
ClientPrivate::ClientPrivate(Client *q_)
: udev(0), monitor(0), q(q_), monitorNotifier(0)
{
}
ClientPrivate::~ClientPrivate()
{
udev_unref(udev);
delete monitorNotifier;
if (monitor)
udev_monitor_unref(monitor);
}
void ClientPrivate::init(const QStringList &subsystemList, ListenToWhat what)
{
udev = udev_new();
if (what != ListenToNone) {
setWatchedSubsystems(subsystemList);
}
}
void ClientPrivate::setWatchedSubsystems(const QStringList &subsystemList)
{
// create a listener
struct udev_monitor *newM = udev_monitor_new_from_netlink(udev, "udev");
if (!newM) {
qWarning("UdevQt: unable to create udev monitor connection");
return;
}
// apply our filters; an empty list means listen to everything
foreach (const QString& subsysDevtype, subsystemList) {
int ix = subsysDevtype.indexOf("/");
if (ix > 0) {
QByteArray subsystem = subsysDevtype.left(ix).toLatin1();
QByteArray devType = subsysDevtype.mid(ix + 1).toLatin1();
udev_monitor_filter_add_match_subsystem_devtype(newM, subsystem.constData(), devType.constData());
} else {
udev_monitor_filter_add_match_subsystem_devtype(newM, subsysDevtype.toLatin1().constData(), NULL);
}
}
// start the new monitor receiving
udev_monitor_enable_receiving(newM);
QSocketNotifier *sn = new QSocketNotifier(udev_monitor_get_fd(newM), QSocketNotifier::Read);
QObject::connect(sn, SIGNAL(activated(int)), q, SLOT(_uq_monitorReadyRead(int)));
// kill any previous monitor
delete monitorNotifier;
if (monitor)
udev_monitor_unref(monitor);
// and save our new one
monitor = newM;
monitorNotifier = sn;
watchedSubsystems = subsystemList;
}
void ClientPrivate::_uq_monitorReadyRead(int fd)
{
Q_UNUSED(fd);
monitorNotifier->setEnabled(false);
struct udev_device *dev = udev_monitor_receive_device(monitor);
monitorNotifier->setEnabled(true);
if (!dev)
return;
Device device(new DevicePrivate(dev, false));
QByteArray action(udev_device_get_action(dev));
if (action == "add") {
emit q->deviceAdded(device);
} else if (action == "remove") {
emit q->deviceRemoved(device);
} else if (action == "change") {
emit q->deviceChanged(device);
} else if (action == "online") {
emit q->deviceOnlined(device);
} else if (action == "offline") {
emit q->deviceOfflined(device);
} else {
qWarning("UdevQt: unhandled device action \"%s\"", action.constData());
}
}
DeviceList ClientPrivate::deviceListFromEnumerate(struct udev_enumerate *en)
{
DeviceList ret;
struct udev_list_entry *list, *entry;
udev_enumerate_scan_devices(en);
list = udev_enumerate_get_list_entry(en);
udev_list_entry_foreach(entry, list) {
struct udev_device *ud = udev_device_new_from_syspath(udev_enumerate_get_udev(en),
udev_list_entry_get_name(entry));
if (!ud)
continue;
ret << Device(new DevicePrivate(ud, false));
}
udev_enumerate_unref(en);
return ret;
}
Client::Client(QObject *parent)
: QObject(parent)
, d(new ClientPrivate(this))
{
d->init(QStringList(), ClientPrivate::ListenToNone);
}
Client::Client(const QStringList& subsystemList, QObject *parent)
: QObject(parent)
, d(new ClientPrivate(this))
{
d->init(subsystemList, ClientPrivate::ListenToList);
}
Client::~Client()
{
delete d;
}
QStringList Client::watchedSubsystems() const
{
// we're watching a specific list
if (!d->watchedSubsystems.isEmpty())
return d->watchedSubsystems;
// we're not watching anything
if (!d->monitor)
return QStringList();
// we're watching everything: figure out what "everything" currently is
// we don't cache it, since it may be subject to change, depending on hotplug
struct udev_enumerate *en = udev_enumerate_new(d->udev);
udev_enumerate_scan_subsystems(en);
QStringList s = listFromListEntry(udev_enumerate_get_list_entry(en));
udev_enumerate_unref(en);
return s;
}
void Client::setWatchedSubsystems(const QStringList &subsystemList)
{
d->setWatchedSubsystems(subsystemList);
}
DeviceList Client::devicesByProperty(const QString &property, const QVariant &value)
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
if (value.isValid()) {
udev_enumerate_add_match_property(en, property.toLatin1().constData(), value.toString().toLatin1().constData());
} else {
udev_enumerate_add_match_property(en, property.toLatin1().constData(), NULL);
}
return d->deviceListFromEnumerate(en);
}
DeviceList Client::allDevices()
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
return d->deviceListFromEnumerate(en);
}
DeviceList Client::devicesBySubsystem(const QString &subsystem)
{
struct udev_enumerate *en = udev_enumerate_new(d->udev);
udev_enumerate_add_match_subsystem(en, subsystem.toLatin1().constData());
return d->deviceListFromEnumerate(en);
}
Device Client::deviceByDeviceFile(const QString &deviceFile)
{
struct stat sb;
if (stat(deviceFile.toLatin1().constData(), &sb) != 0)
return Device();
struct udev_device *ud = 0;
if (S_ISBLK(sb.st_mode))
ud = udev_device_new_from_devnum(d->udev, 'b', sb.st_rdev);
else if (S_ISCHR(sb.st_mode))
ud = udev_device_new_from_devnum(d->udev, 'c', sb.st_rdev);
if (!ud)
return Device();
return Device(new DevicePrivate(ud, false));
}
Device Client::deviceBySysfsPath(const QString &sysfsPath)
{
struct udev_device *ud = udev_device_new_from_syspath(d->udev, sysfsPath.toLatin1().constData());
if (!ud)
return Device();
return Device(new DevicePrivate(ud, false));
}
Device Client::deviceBySubsystemAndName(const QString &subsystem, const QString &name)
{
struct udev_device *ud = udev_device_new_from_subsystem_sysname(d->udev,
subsystem.toLatin1().constData(),
name.toLatin1().constData());
if (!ud)
return Device();
return Device(new DevicePrivate(ud, false));
}
}
#include "udevqt.moc"
/*
Copyright 2009 Benjamin K. Stuhl <bks24@cornell.edu>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "udevqt.h"
#include "udevqt_p.h"
#include <QtCore/QByteArray>
namespace UdevQt {
DevicePrivate::DevicePrivate(struct udev_device *udev_, bool ref)
: udev(udev_)
{
if (ref)
udev_device_ref(udev);
}
DevicePrivate::~DevicePrivate()
{
udev_device_unref(udev);
}
DevicePrivate &DevicePrivate::operator=(const DevicePrivate &other)
{
udev_device_unref(udev);
udev = udev_device_ref(other.udev);
return *this;
}
QString DevicePrivate::decodePropertyValue(const QByteArray &encoded) const
{
QByteArray decoded;
const int len = encoded.length();
for (int i = 0; i < len; i++) {
quint8 ch = encoded.at(i);
if (ch == '\\') {
if (i + 1 < len && encoded.at(i + 1) == '\\') {
decoded.append('\\');
i++;
continue;
} else if (i + 3 < len && encoded.at(i + 1) == 'x') {