Lets learn something solid like KDE Solid

Solid is an API for accessing device information like disks, networks etc.

Posted by Shubham Chaudhary on November 9, 2013


Well First of all I'm not talking about Solid (one of the four fundamental states of matter), or SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion) here.


The following post is collection of all the information about Solid - a hardware device integration framework for KDE 4 Platform.


What is Solid ?

Solid is an API for accessing device information such as available disks or networks. It does not deal with device drivers, leaving that to the OS. It does not deal with low level device information, leaving that to already existing, and very good tools such as HAL or other underlying subsystems. Solid among other things, provides a hardware discovery layer which allows you to detect and use devices regardless of operating system or architecture. 
One of the long term problems with UNIX ease of use has been access to removable devices. Many solutions have come up in the past, including kernel-based automounters (Mandrake of several years ago).  KDE is building a generic API for removable devices so that applications don't have to know what's happening in the background. And by removable devices, I mean any removable devices, not just storage. Solid already does removable audio devices, laptop batteries and more... It's not all just about removable hardware, but also about what is built into your system. Phonon uses Solid to detect available sound devices on your system, and can seamlessly switch between output devices, including hotpluggable sound devices.

Why is Solid Used ?


Seamless Hardware Interaction [2] : With Solid, KDE developers are able to easily write applications with hardware interaction features. The necessary abstraction to support cross-platform application development is provided by Solid's clear and comprehensive API.

Its aim is not the control of the devices (Solid doesn't let you synchronize your mobile phone with your local address book): Solid looks for devices and gives you access to the information it has about them. This way, you could easily look at the functions of the cpu, or at the driver that handles your camera, or the mount point of your usb pen. In sum: it gives you the possibility of "seeing without touching" your devices.

Now you would ask (at least, I asked myself): "Why should I need this library? I want to control the available hardware, not just see it!"

Well, Solid helps you a lot again: for any device interface, it gives you enough information to easily access it using other libraries or stacks. This way, if you want to manage your camera, you can use Solid to recognize it (you can use Solid::Notifier that will let you know when your camera has been plugged in), and then you can ask Solid to give you the information you need to handle it, for example with GPhoto or any other library you can think of. The same applies for any other plugged device: DVB cards (once recognized, Solid gives you the name of the associated device), audio cards (you can use ALSA, OSS or whatever you want: Solid knows the data to access it), portable media players, network cards, et cetera. Moreover, it lets you check if you're connected to any network or not, and you can use Solid to tell the system to connect (that is, you can ask Solid: "Give me access to the network, I don't want to care about details").

Anyway, some other things need to be said about network devices and Bluetooth. For these two classes of devices, Solid provides the "Control" namespace: that is, it lets you control them directly, without using external libraries. This means that with Solid, you can even handle your wireless or wired network interfaces, associate them to an essid, and choose ip configuration for them. You can even access your phone through Bluetooth, and so on.


The "listing" part of Solid resides in kdelibs, while the Control namespace is in kdebase.

Architecture Summary


Solid Class Diagram


Solid was implemented using a frontend/backend approach aiming portability among platforms like Linux and Windows[2]. The frontend provides the high-level API for developers using Solid and backends deal with the specific hardware issues for the different platforms.

Frontend View

The frontend classes provide the API for developers and are also wrappers for several kinds of devices. All frontend clases are available in kdelibs/solid/solid.

Solid::DeviceNotifier

The device notifier is a singleton used to obtain information about the hardware available on the system. It provides to applications the unique entry point for hardware discovery and/or notifications about changes (with the use of Solid::DeviceNotifier::deviceAdded(const QString) and Solid::DeviceNotifier::deviceRemoved(const QString) signals). This class calls the following Solid::DeviceManager.

Solid::DeviceManager

This (private) class maintains the state of all devices currently available on the system. Through it is possible to get, for example, the list of all devices or a list of device matching with some criteria (using Solid::Predicate).

Solid::Device

This class represents a general hardware device. A device contains one or more device interfaces (capabilities).

Solid::DeviceInterface

A device interface represents a certain feature that a device contains. This class is on the top of the device interfaces inheritance tree. All specialized device interfaces implement it.

Specialized classes (Solid::Processor, Solid::OpticalDrive, Solid::Battery, etc.)

These classes actually represent the capabilities that a device can have. All classes extend Solid::DeviceInterface.

Backend View

A Solid backend deal with the platform-specific ways of handle devices. Developers using libsolid do not use the backend classes directly. Applications do it through frontend/wrapping classes in the Solid namespace.


All backends have to implement the interfaces in kdelibs/solid/solid/ifaces (namespace Solid::Ifaces) correspondent to its devices. These interfaces are the basics of which API a given device has to provide to the frontend classes.


Tuitorials





Tuitorial 1: Development/Tutorials/Solid/Device Discovery
Listing Devices
How to use the Solid core library to discover the hardware and interact with the system.


Prerequisites

  • A working KDE4 development environment. Documentation on setting up a KDE environment can be found here.

Listing Devices

Our first program will be a simple console based app that gets a list of all the hardware devices and prints them out to the screen.
    Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
This gets us the device manager. All the devices are queried through and returned from the device manager. Once we have the list of devices we can interact with them as follows:
foreach( Solid::Device device, Solid::Device::allDevices() )
{
//print the name of device
kDebug() << device.udi();
}
device.udi() returns the Unique Device Identifier for the device as a QString. Even if you have more than one identical device, the UDI is guaranteed to be unique. For example if you have a MythTV box with two PVR-250 T.V. capture cards in it, you will be able to refer to card #1 and #2 by their respective UDI.
The complete program along with the CMake files necessary to build it can be found under "kdeexamples/solid/tutorial1/".

Searching for specific devices

This second program makes uses of filters built into the solid framework. Using these filters you can list only devices according to supported capabilities, sub-devices of a given parent, and various predicates. In our example we'll be limiting our list to only audio hardware. A full list of capabilities can be viewed under the Solid::Capability namespace.
Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
 
//get a list of all devices that are AudioHw
foreach (Solid::Device device, Solid::Device::listFromType(Solid::DeviceInterface::AudioInterface, QString()))
{
kDebug() << device.udi().toLatin1().constData();
}
In this example Solid::DeviceManager::findDevicesFromQuery looks for a device with any parent and the Solid::Capability::AudioHw capability. If we had wanted to specify an AudioHw device with the parent "real_specific_parent" it would look like this:
Solid::Device::listFromType(Solid::Capability::AudioHw,"real_specific_parent" )
The complete program along with the CMake files required to build it can be found under "kdeexamples/solid/tutorial2/".

What do we do with a device once we get it?

Now that we got a device, what do we do with it? First let's look at the relationship between the Solid::Device and Solid::Capability. A Solid::Device can contain many Solid::Capability. A device can be tested to have a capability in the following way:
Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
 
//get a Processor
QList<Solid::Device> list = Solid::Device::listFromType(Solid::DeviceInterface::Processor, QString());
 
//take the first processor
Solid::Device device = list[0];
if(device.is<Solid::Processor>() ) kDebug() << "We've got a processor!";
else kDebug() << "Device is not a processor.";
 
Solid::Processor *processor = device.as<Solid::Processor>();
kDebug() << "This processors maximum speed is:" << processor->maxSpeed();
To actually use this device as a processor we need to do the following:
    Solid::Processor *processor = device.as<Solid::Processor>();
The complete program along with the CMake files required to build it can be found under "kdeexamples/solid/tutorial3/".

solid-hardware tool

kdebase-runtime provides solid-hardware, a command line tool to investigate available devices.
Listing udi for all installed devices:
solid-hardware list
Listing full details for all installed devices:
solid-hardware list details
Listing all audio hardware devices:
solid-hardware query 'IS AudioInterface'







Tuitorial 2: Development/Tutorials/Solid/Network Management



Accessing Network Information
How to use the Solid system to get information about the network

Prerequisites

This tutorial assumes that you have read Introduction to Solid and are familiar with the Solid hardware framework. If you want to use any backends other than the fake backends provided in kdelibs, you will need to compile and install kdebase.

Features of the Solid Network Manager

The Solid Network Manager provides many useful features that have, up until now, been missing from KDE. These include:
  • Notification of connection state. This allows applications to know when there is no internet connection, allowing them to not bother the user with "Connection Error" messages
  • Notification of wireless connection state.
  • Access to network devices and interfaces.
  • Device <-> interface cross-referencing.
Note that there is a difference between the devices and the interfaces. The device is a representation of the device itself and all the things that normally are associated with a PCI/USB device such as: bus address, IRQ, etc. The interface is the name of the device e.g. 'eth0' which is used for commands like 'ifconfig.'

Let's begin

Our first program is going to be the most common use of the network manager, checking the network status of the system. This will be useful for programs like KMail which will be able to see if the computer has network connectivity. It would then be able to judge whether or not it should check for mail.
//test to see if networking is enabled on the system
if(Solid::Networking::status() == Solid::Networking::Connected)
{
kDebug() << "Networking is enabled. Feel free to go online!";
}
else
{
kDebug() << "Network not available.";
}
To get informed about changes in network connectivity you'll have to connect to the events of Solid::Networking::notifier().

Cross-referencing devices to interfaces

It is no longer required for the user to figure out which device corresponds to a given interface as the NetworkManager has the ability to cross-reference a device to its interface name. This can be done with the following code:
//get a reference to the device manager
Solid::DeviceManager &manager = Solid::DeviceManager::self();
 
//get a network device
Solid::DeviceList netlist = manager.findDevicesFromQuery(Solid::Capability::NetworkHw, QString());
 
//check to see if no network devices were found
if(netlist.empty() )
{
kDebug() << "No network devices found!";
}
 
Solid::Device device = netlist[0];
Solid::NetworkHw *netdev = device.as<Solid::NetworkHw>();
//keep the program from crashing in the event that there's a bug in solid
if(!netdev)
{
kDebug() << "Device could not be converted. There is a bug.";
return 0;
}
 
kDebug() << "The iface of" << device.udi() << "is" << netdev->ifaceName();



Tuitorial 3: Development/Tutorials/Solid/Device Actions

Creating a Device Action







When your application is interested in registering actions with the system for removable hardware

Introduction


When a new data device is inserted or detected by Solid, the hardware awareness framework introduced in KDE Platform 4, it gets added to the Device Notifier (a Plasma widget that is responsible for handling device events), Places list and other relevant areas in the user interface.

Each device has a set of related actions which the user can perform on the device, depending on the device type and its contents. For example, when the media is an audio CD, the Device Notifier may offer to play that CD using Amarok. The default actions are not a part of Plasma Desktop, however; rather, each action is defined by a simple .desktop file that is installed by the application that handles the action (e.g. Amarok in our Audio CD example), and goes away when the application is removed.

You can add your own actions and modify existing ones using the Device Actions system setting module; however, such changes are limited to the user that requests the change. If you want to install a custom action along with your application, you have to dig a bit deeper.

Anatomy of an action

An Action file is a desktop configuration file similar to the following one:
[Desktop Entry]
X-KDE-Solid-Predicate=OpticalDisc.availableContent & 'Audio'
Type=Service
Actions=Play;
 
[Desktop Action Play]
Name=Play Audio CD with Amarok
Name[fr]=Jouer CD Audio avec Amarok
# names in other languages
Icon=amarok
Exec=amarok --cdplay %f

Actions and devices

The Device Notifier gets the devices and their corresponding actions by interrogating thehotplug Plasma DataEngine. The hotplugDataEngine gets the set of devices from Solid and the set of actions from the subdirectories ./solid/actions relative to the application settings path in KDE. The set of actions pertaining to each device is then obtained by evaluating the Solid Predicate specified in the action against the physical and logical properties of the device; if the predicate holds, the action is included. This is, of course, not limited to Plasma Desktop: any application can similarly query Solid for the same actions.

Action predicates

The predicate for each action is specified in the entry X-KDE-Solid-Predicate. The syntax of the predicate allows to construct an object of class Solid::Predicate out of it.
Atomic predicates can be of the form
  • DeviceClass.attribute == value
  • DeviceClass.attribute & value
the latter form meaning that the Solid attribute may have a set of values, and the specified value must be a part of that set.
For example, the predicate OpticalDisc.availableContent & 'Audio' means that the device medium is an optical disc and that it contains audio tracks and possibly something else, while the hypothetical predicate OpticalDisc.availableContent == 'Audio'means that a matching device contains audio tracks and nothing else.
Atomic predicates can be composed using the keywords AND and OR and parentheses. In practice, it is easiest to create a custom action with System Settings and peek the description from the custom action desktop file (within the user profile directory).

Executing actions

A matching action can be selected for execution by the user. When that happens, the command line in the Exec key of the action is executed given the device as a parameter. The location and value of the parameter is specified in the following way:
%f
Device mount point location, if applicable
%d
Device special file path
%i
Device identifier, as if returned by the command solid-hardware
So you are free to choose whatever command syntax your application supports. Note, however, that the forms %d and %i are deprecated by the Free Desktop standard and may be discontinued.

Installing actions

You install system-wide actions in the directory where the hotplug data engine will look for them (see above). The action is available immediately after installation.

Reference Links:
  1. https://techbase.kde.org/Development/Tutorials/Solid
  2. https://techbase.kde.org/Development/Architecture/KDE4/Solid
  3. https://dot.kde.org/2007/04/24/road-kde-4-solid-brings-hardware-configuration-and-control-kde
  4. https://techbase.kde.org/Development/Tutorials/Solid
  5. https://techbase.kde.org/Development/Tutorials/Solid/Device_Discovery
  6. https://techbase.kde.org/Development/Tutorials/Solid/Network_Management
  7. https://techbase.kde.org/Development/Tutorials/Solid/Device_Actions
  8. https://api.kde.org/4.x-api/kdelibs-apidocs/solid/html/namespaceSolid.html
And now scroll down if you want to see :
    Solid Namespace Reference

    Namespaces

    namespace  Ifaces
    namespace  Networking
    namespace  PowerManagement
    namespace  PredicateParse
    namespace  XdgBaseDirs

    Classes

    class  AcAdapter
    This device interface is available on AC adapters. More...
    class  AcAdapterPrivate
    class  AudioInterface
    This device interface is available on interfaces exposed by sound cards. More...
    class  AudioInterfacePrivate
    class  Battery
    This device interface is available on batteries. More...
    class  BatteryPrivate
    class  Block
    This device interface is available on block devices. More...
    class  BlockPrivate
    class  Button
    This device interface is available on button devices. More...
    class  ButtonPrivate
    class  Camera
    This device interface is available on digital camera devices. More...
    class  CameraPrivate
    class  CleanUpGlobalStatic
    class  Device
    This class allows applications to deal with devices available in the underlying system. More...
    class  DeviceInterface
    Base class of all the device interfaces. More...
    class  DeviceInterfacePrivate
    class  DeviceManagerPrivate
    class  DeviceManagerStorage
    class  DeviceNotifier
    This class allow to query the underlying system to obtain information about the hardware available. More...
    class  DevicePrivate
    class  DvbInterface
    This device interface is available on Digital Video Broadcast (DVB) devices. More...
    class  DvbInterfacePrivate
    class  GenericInterface
    Generic interface to deal with a device. More...
    class  GenericInterfacePrivate
    class  InternetGateway
    class  InternetGatewayPrivate
    class  ManagerBasePrivate
    class  NetworkingPrivate
    class  NetworkInterface
    This device interface is available on network interfaces. More...
    class  NetworkInterfacePrivate
    class  NetworkShare
    NetworkShare interface. More...
    class  NetworkSharePrivate
    class  OpticalDisc
    This device interface is available on optical discs. More...
    class  OpticalDiscPrivate
    class  OpticalDrive
    This device interface is available on CD-R*,DVD*,Blu-Ray,HD-DVD drives. More...
    class  OpticalDrivePrivate
    class  PortableMediaPlayer
    This class implements Portable Media Player device interface and represents a portable media player attached to the system.More...
    class  PortableMediaPlayerPrivate
    class  PowerManagementPrivate
    class  Predicate
    This class implements predicates for devices. More...
    class  Processor
    This device interface is available on processors. More...
    class  ProcessorPrivate
    class  SerialInterface
    This device interface is available on serial interfaces. More...
    class  SerialInterfacePrivate
    class  SmartCardReader
    This device interface is available on smart card readers. More...
    class  SmartCardReaderPrivate
    class  StorageAccess
    This device interface is available on volume devices to access them (i.e. More...
    class  StorageAccessPrivate
    class  StorageDrive
    This device interface is available on storage devices. More...
    class  StorageDrivePrivate
    class  StorageVolume
    This device interface is available on volume devices. More...
    class  StorageVolumePrivate
    class  Video
    This device interface is available on video devices. More...
    class  VideoPrivate

    Typedefs

    typedef void(* CleanUpFunction )()

    Enumerations

    enum  ErrorType {
      NoError = 0, UnauthorizedOperationDeviceBusyOperationFailed,
      UserCanceledInvalidOptionMissingDriver
    }

    Typedef Documentation


    typedef void(* Solid::CleanUpFunction)()
    Definition at line 60 of file soliddefs_p.h.

    Enumeration Type Documentation


    Enumerator:
    NoError 
    UnauthorizedOperation 
    DeviceBusy 
    OperationFailed 
    UserCanceled 
    InvalidOption 
    MissingDriver 
    Definition at line 27 of file solidnamespace.h.