commit
b90fb73480
@ -249,6 +249,10 @@ optional_component(DEVICEKIT ON "Devices: DeviceKit backend"
|
||||
DEPENDS "D-Bus support" HAVE_DBUS
|
||||
)
|
||||
|
||||
optional_component(UDISKS2 ON "Devices: UDisks2 backend"
|
||||
DEPENDS "D-Bus support" HAVE_DBUS
|
||||
)
|
||||
|
||||
optional_component(SPOTIFY_BLOB ON "Spotify support: non-GPL binary helper"
|
||||
DEPENDS "protobuf" PROTOBUF_FOUND PROTOBUF_PROTOC_EXECUTABLE
|
||||
DEPENDS "libspotify" SPOTIFY_FOUND
|
||||
|
@ -964,6 +964,34 @@ if(HAVE_DBUS)
|
||||
dbus/udisksdevice)
|
||||
endif(HAVE_DEVICEKIT)
|
||||
|
||||
if(HAVE_UDISKS2)
|
||||
set_source_files_properties(dbus/org.freedesktop.DBus.ObjectManager.xml
|
||||
PROPERTIES NO_NAMESPACE dbus/objectmanager INCLUDE dbus/metatypes.h)
|
||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Filesystem.xml
|
||||
PROPERTIES NO_NAMESPACE dbus/udisks2filesystem INCLUDE dbus/metatypes.h)
|
||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Block.xml
|
||||
PROPERTIES NO_NAMESPACE dbus/udisks2block INCLUDE dbus/metatypes.h)
|
||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Drive.xml
|
||||
PROPERTIES NO_NAMESPACE dbus/udisks2drive INCLUDE dbus/metatypes.h)
|
||||
set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml
|
||||
PROPERTIES NO_NAMESPACE dbus/udisks2job INCLUDE dbus/metatypes.h)
|
||||
qt4_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.DBus.ObjectManager.xml
|
||||
dbus/objectmanager)
|
||||
qt4_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Filesystem.xml
|
||||
dbus/udisks2filesystem)
|
||||
qt4_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Block.xml
|
||||
dbus/udisks2block)
|
||||
qt4_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Drive.xml
|
||||
dbus/udisks2drive)
|
||||
qt4_add_dbus_interface(SOURCES
|
||||
dbus/org.freedesktop.UDisks2.Job.xml
|
||||
dbus/udisks2job)
|
||||
endif(HAVE_UDISKS2)
|
||||
|
||||
# Wiimotedev interface classes
|
||||
if(ENABLE_WIIMOTEDEV)
|
||||
qt4_add_dbus_interface(SOURCES
|
||||
@ -999,6 +1027,11 @@ optional_source(HAVE_DEVICEKIT
|
||||
HEADERS devices/devicekitlister.h
|
||||
)
|
||||
|
||||
optional_source(HAVE_UDISKS2
|
||||
SOURCES devices/udisks2lister.cpp
|
||||
HEADERS devices/udisks2lister.h
|
||||
)
|
||||
|
||||
# Libgpod device backend
|
||||
optional_source(HAVE_LIBGPOD
|
||||
INCLUDE_DIRECTORIES ${LIBGPOD_INCLUDE_DIRS}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#cmakedefine HAVE_SKYDRIVE
|
||||
#cmakedefine HAVE_SPARKLE
|
||||
#cmakedefine HAVE_SPOTIFY_DOWNLOADER
|
||||
#cmakedefine HAVE_UDISKS2
|
||||
#cmakedefine HAVE_VK
|
||||
#cmakedefine HAVE_WIIMOTEDEV
|
||||
#cmakedefine TAGLIB_HAS_OPUS
|
||||
|
@ -125,5 +125,8 @@ void RegisterMetaTypes() {
|
||||
qDBusRegisterMetaType<MprisPlaylist>();
|
||||
qDBusRegisterMetaType<MaybePlaylist>();
|
||||
qDBusRegisterMetaType<MprisPlaylistList>();
|
||||
|
||||
qDBusRegisterMetaType<InterfacesAndProperties>();
|
||||
qDBusRegisterMetaType<ManagedObjectList>();
|
||||
#endif
|
||||
}
|
||||
|
@ -19,7 +19,14 @@
|
||||
#define DBUS_METATYPES_H_
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QDBusObjectPath>
|
||||
|
||||
Q_DECLARE_METATYPE(QList<QByteArray>);
|
||||
Q_DECLARE_METATYPE(QList<QByteArray>)
|
||||
|
||||
typedef QMap<QString, QVariantMap> InterfacesAndProperties;
|
||||
typedef QMap<QDBusObjectPath, InterfacesAndProperties> ManagedObjectList;
|
||||
|
||||
Q_DECLARE_METATYPE(InterfacesAndProperties)
|
||||
Q_DECLARE_METATYPE(ManagedObjectList)
|
||||
|
||||
#endif // DBUS_METATYPES_H_
|
||||
|
19
src/dbus/org.freedesktop.DBus.ObjectManager.xml
Normal file
19
src/dbus/org.freedesktop.DBus.ObjectManager.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.ObjectManager">
|
||||
<method name="GetManagedObjects">
|
||||
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ManagedObjectList"/>
|
||||
</method>
|
||||
<signal name="InterfacesAdded">
|
||||
<arg name="object" type="o"/>
|
||||
<arg name="interfaces" type="a{sa{sv}}"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="InterfacesAndProperties"/>
|
||||
</signal>
|
||||
<signal name="InterfacesRemoved">
|
||||
<arg type="o" name="object_path"/>
|
||||
<arg type="as" name="interfaces"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
9
src/dbus/org.freedesktop.UDisks2.Block.xml
Normal file
9
src/dbus/org.freedesktop.UDisks2.Block.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.UDisks2.Block">
|
||||
<property type="o" name="Drive" access="read"/>
|
||||
<property type="s" name="IdLabel" access="read"/>
|
||||
<property type="s" name="IdUUID" access="read"/>
|
||||
</interface>
|
||||
</node>
|
17
src/dbus/org.freedesktop.UDisks2.Drive.xml
Normal file
17
src/dbus/org.freedesktop.UDisks2.Drive.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.UDisks2.Drive">
|
||||
<method name="Eject">
|
||||
<arg type="a{sv}" name="options" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
|
||||
</method>
|
||||
<property type="s" name="Vendor" access="read"/>
|
||||
<property type="s" name="Model" access="read"/>
|
||||
<property type="s" name="Revision" access="read"/>
|
||||
<property type="s" name="Serial" access="read"/>
|
||||
<property type="s" name="Id" access="read"/>
|
||||
<property type="b" name="MediaRemovable" access="read"/>
|
||||
<property type="t" name="Size" access="read"/>
|
||||
</interface>
|
||||
</node>
|
18
src/dbus/org.freedesktop.UDisks2.Filesystem.xml
Normal file
18
src/dbus/org.freedesktop.UDisks2.Filesystem.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.UDisks2.Filesystem">
|
||||
<method name="Mount">
|
||||
<arg type="a{sv}" name="options" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
|
||||
<arg type="s" name="mount_path" direction="out"/>
|
||||
</method>
|
||||
<method name="Unmount">
|
||||
<arg type="a{sv}" name="options" direction="in"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
|
||||
</method>
|
||||
<property type="aay" name="MountPoints" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QList<QByteArray>"/>
|
||||
</property>
|
||||
</interface>
|
||||
</node>
|
11
src/dbus/org.freedesktop.UDisks2.Job.xml
Normal file
11
src/dbus/org.freedesktop.UDisks2.Job.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<interface name="org.freedesktop.UDisks2.Job">
|
||||
<property name="Operation" type="s" access="read"/>
|
||||
<property name="Objects" type="ao" access="read"/>
|
||||
<signal name="Completed">
|
||||
<arg name="success" type="b"/>
|
||||
<arg name="message" type="s"/>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
@ -59,6 +59,9 @@
|
||||
#ifdef HAVE_LIBMTP
|
||||
#include "mtpdevice.h"
|
||||
#endif
|
||||
#ifdef HAVE_UDISKS2
|
||||
#include "udisks2lister.h"
|
||||
#endif
|
||||
|
||||
using std::bind;
|
||||
|
||||
@ -191,6 +194,9 @@ DeviceManager::DeviceManager(Application* app, QObject* parent)
|
||||
#ifdef HAVE_DEVICEKIT
|
||||
AddLister(new DeviceKitLister);
|
||||
#endif
|
||||
#ifdef HAVE_UDISKS2
|
||||
AddLister(new Udisks2Lister);
|
||||
#endif
|
||||
#ifdef HAVE_GIO
|
||||
AddLister(new GioLister);
|
||||
#endif
|
||||
@ -228,7 +234,10 @@ void DeviceManager::LoadAllDevices() {
|
||||
for (const DeviceDatabaseBackend::Device& device : devices) {
|
||||
DeviceInfo info;
|
||||
info.InitFromDb(device);
|
||||
|
||||
beginInsertRows(QModelIndex(), devices_.count(), devices_.count());
|
||||
devices_ << info;
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
|
||||
|
368
src/devices/udisks2lister.cpp
Normal file
368
src/devices/udisks2lister.cpp
Normal file
@ -0,0 +1,368 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2016, Valeriy Malov <jazzvoid@gmail.com>
|
||||
|
||||
Clementine 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
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "udisks2lister.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/utilities.h"
|
||||
#include "dbus/objectmanager.h"
|
||||
#include "dbus/udisks2block.h"
|
||||
#include "dbus/udisks2drive.h"
|
||||
#include "dbus/udisks2filesystem.h"
|
||||
#include "dbus/udisks2job.h"
|
||||
|
||||
constexpr char Udisks2Lister::udisks2_service_[];
|
||||
|
||||
Udisks2Lister::Udisks2Lister() {}
|
||||
|
||||
Udisks2Lister::~Udisks2Lister() {}
|
||||
|
||||
QStringList Udisks2Lister::DeviceUniqueIDs() {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
return device_data_.keys();
|
||||
}
|
||||
|
||||
QVariantList Udisks2Lister::DeviceIcons(const QString& id) {
|
||||
return QVariantList();
|
||||
}
|
||||
|
||||
QString Udisks2Lister::DeviceManufacturer(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return "";
|
||||
return device_data_[id].vendor;
|
||||
}
|
||||
|
||||
QString Udisks2Lister::DeviceModel(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return "";
|
||||
return device_data_[id].model;
|
||||
}
|
||||
|
||||
quint64 Udisks2Lister::DeviceCapacity(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return 0;
|
||||
return device_data_[id].capacity;
|
||||
}
|
||||
|
||||
quint64 Udisks2Lister::DeviceFreeSpace(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return 0;
|
||||
return device_data_[id].free_space;
|
||||
}
|
||||
|
||||
QVariantMap Udisks2Lister::DeviceHardwareInfo(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return QVariantMap();
|
||||
|
||||
QVariantMap result;
|
||||
|
||||
const auto& data = device_data_[id];
|
||||
result[QT_TR_NOOP("DBus path")] = data.dbus_path;
|
||||
result[QT_TR_NOOP("Serial number")] = data.serial;
|
||||
result[QT_TR_NOOP("Mount points")] = data.mount_paths.join(", ");
|
||||
result[QT_TR_NOOP("Parition label")] = data.label;
|
||||
result[QT_TR_NOOP("UUID")] = data.uuid;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString Udisks2Lister::MakeFriendlyName(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return "";
|
||||
return device_data_[id].friendly_name;
|
||||
}
|
||||
|
||||
QList<QUrl> Udisks2Lister::MakeDeviceUrls(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return QList<QUrl>();
|
||||
return QList<QUrl>() << QUrl::fromLocalFile(
|
||||
device_data_[id].mount_paths.at(0));
|
||||
}
|
||||
|
||||
void Udisks2Lister::UnmountDevice(const QString& id) {
|
||||
QReadLocker locker(&device_data_lock_);
|
||||
if (!device_data_.contains(id)) return;
|
||||
|
||||
OrgFreedesktopUDisks2FilesystemInterface filesystem(
|
||||
udisks2_service_, device_data_[id].dbus_path,
|
||||
QDBusConnection::systemBus());
|
||||
|
||||
if (filesystem.isValid()) {
|
||||
auto unmount_result = filesystem.Unmount(QVariantMap());
|
||||
unmount_result.waitForFinished();
|
||||
|
||||
if (unmount_result.isError()) {
|
||||
qLog(Warning) << "Failed to unmount " << id << ": "
|
||||
<< unmount_result.error();
|
||||
return;
|
||||
}
|
||||
|
||||
OrgFreedesktopUDisks2DriveInterface drive(udisks2_service_,
|
||||
device_data_[id].dbus_drive_path,
|
||||
QDBusConnection::systemBus());
|
||||
|
||||
if (drive.isValid()) {
|
||||
auto eject_result = drive.Eject(QVariantMap());
|
||||
eject_result.waitForFinished();
|
||||
|
||||
if (eject_result.isError())
|
||||
qLog(Warning) << "Failed to eject " << id << ": "
|
||||
<< eject_result.error();
|
||||
}
|
||||
|
||||
device_data_.remove(id);
|
||||
DeviceRemoved(id);
|
||||
}
|
||||
}
|
||||
|
||||
void Udisks2Lister::UpdateDeviceFreeSpace(const QString& id) {
|
||||
QWriteLocker locker(&device_data_lock_);
|
||||
device_data_[id].free_space =
|
||||
Utilities::FileSystemFreeSpace(device_data_[id].mount_paths.at(0));
|
||||
|
||||
emit DeviceChanged(id);
|
||||
}
|
||||
|
||||
void Udisks2Lister::Init() {
|
||||
udisks2_interface_.reset(new OrgFreedesktopDBusObjectManagerInterface(
|
||||
udisks2_service_, "/org/freedesktop/UDisks2",
|
||||
QDBusConnection::systemBus()));
|
||||
|
||||
QDBusPendingReply<ManagedObjectList> reply =
|
||||
udisks2_interface_->GetManagedObjects();
|
||||
reply.waitForFinished();
|
||||
|
||||
if (!reply.isValid()) {
|
||||
qLog(Warning) << "Error enumerating udisks2 devices:"
|
||||
<< reply.error().name() << reply.error().message();
|
||||
udisks2_interface_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const QDBusObjectPath& path : reply.value().keys()) {
|
||||
auto partition_data = ReadPartitionData(path);
|
||||
|
||||
if (!partition_data.dbus_path.isEmpty()) {
|
||||
QWriteLocker locker(&device_data_lock_);
|
||||
device_data_[partition_data.unique_id()] = partition_data;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& id : device_data_.keys()) {
|
||||
emit DeviceAdded(id);
|
||||
}
|
||||
|
||||
connect(udisks2_interface_.get(),
|
||||
SIGNAL(InterfacesAdded(QDBusObjectPath, InterfacesAndProperties)),
|
||||
SLOT(DBusInterfaceAdded(QDBusObjectPath, InterfacesAndProperties)));
|
||||
connect(udisks2_interface_.get(),
|
||||
SIGNAL(InterfacesRemoved(QDBusObjectPath, QStringList)),
|
||||
SLOT(DBusInterfaceRemoved(QDBusObjectPath, QStringList)));
|
||||
}
|
||||
|
||||
void Udisks2Lister::DBusInterfaceAdded(
|
||||
const QDBusObjectPath& path, const InterfacesAndProperties& interfaces) {
|
||||
for (auto interface = interfaces.constBegin();
|
||||
interface != interfaces.constEnd(); ++interface) {
|
||||
if (interface.key() != "org.freedesktop.UDisks2.Job") continue;
|
||||
|
||||
std::shared_ptr<OrgFreedesktopUDisks2JobInterface> job =
|
||||
std::make_shared<OrgFreedesktopUDisks2JobInterface>(
|
||||
udisks2_service_, path.path(), QDBusConnection::systemBus());
|
||||
|
||||
if (!job->isValid()) continue;
|
||||
|
||||
bool is_mount_job = false;
|
||||
if (job->operation() == "filesystem-mount") {
|
||||
is_mount_job = true;
|
||||
} else if (job->operation() == "filesystem-unmount") {
|
||||
is_mount_job = false;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto mounted_partitions = job->objects();
|
||||
|
||||
if (mounted_partitions.isEmpty()) {
|
||||
qLog(Warning) << "Empty Udisks2 mount/umount job " << path.path();
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
QMutexLocker locker(&jobs_lock_);
|
||||
qLog(Debug) << "Adding pending job | DBus Path = " << job->path()
|
||||
<< " | IsMountJob = " << is_mount_job
|
||||
<< " | First partition = " << mounted_partitions.at(0).path();
|
||||
mounting_jobs_[path].dbus_interface = job;
|
||||
mounting_jobs_[path].is_mount = is_mount_job;
|
||||
mounting_jobs_[path].mounted_partitions = mounted_partitions;
|
||||
connect(job.get(), SIGNAL(Completed(bool, const QString&)),
|
||||
SLOT(JobCompleted(bool, const QString&)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Udisks2Lister::DBusInterfaceRemoved(const QDBusObjectPath& path,
|
||||
const QStringList& ifaces) {
|
||||
if (!isPendingJob(path)) RemoveDevice(path);
|
||||
}
|
||||
|
||||
bool Udisks2Lister::isPendingJob(const QDBusObjectPath& job_path) {
|
||||
QMutexLocker locker(&jobs_lock_);
|
||||
|
||||
if (!mounting_jobs_.contains(job_path)) return false;
|
||||
|
||||
mounting_jobs_.remove(job_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Udisks2Lister::RemoveDevice(const QDBusObjectPath& device_path) {
|
||||
QWriteLocker locker(&device_data_lock_);
|
||||
QString id;
|
||||
for (const auto& data : device_data_) {
|
||||
if (data.dbus_path == device_path.path()) {
|
||||
id = data.unique_id();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id.isEmpty()) return;
|
||||
|
||||
qLog(Debug) << "UDisks2 device removed: " << device_path.path();
|
||||
device_data_.remove(id);
|
||||
DeviceRemoved(id);
|
||||
}
|
||||
|
||||
QList<QDBusObjectPath> Udisks2Lister::GetMountedPartitionsFromDBusArgument(
|
||||
const QDBusArgument& input) {
|
||||
QList<QDBusObjectPath> result;
|
||||
|
||||
input.beginArray();
|
||||
while (!input.atEnd()) {
|
||||
QDBusObjectPath extractedPath;
|
||||
input >> extractedPath;
|
||||
result.push_back(extractedPath);
|
||||
}
|
||||
input.endArray();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Udisks2Lister::JobCompleted(bool success, const QString& message) {
|
||||
auto job = qobject_cast<OrgFreedesktopUDisks2JobInterface*>(sender());
|
||||
QDBusObjectPath jobPath(job->path());
|
||||
|
||||
if (!job->isValid() || !success || !mounting_jobs_.contains(jobPath)) return;
|
||||
|
||||
qLog(Debug) << "Pending Job Completed | Path = " << job->path()
|
||||
<< " | Mount? = " << mounting_jobs_[jobPath].is_mount
|
||||
<< " | Success = " << success;
|
||||
|
||||
for (const auto& mounted_object :
|
||||
mounting_jobs_[jobPath].mounted_partitions) {
|
||||
auto partition_data = ReadPartitionData(mounted_object);
|
||||
if (partition_data.dbus_path.isEmpty()) continue;
|
||||
|
||||
mounting_jobs_[jobPath].is_mount
|
||||
? HandleFinishedMountJob(partition_data)
|
||||
: HandleFinishedUnmountJob(partition_data, mounted_object);
|
||||
}
|
||||
}
|
||||
|
||||
void Udisks2Lister::HandleFinishedMountJob(
|
||||
const Udisks2Lister::PartitionData& partition_data) {
|
||||
qLog(Debug) << "UDisks2 mount job finished: Drive = "
|
||||
<< partition_data.dbus_drive_path
|
||||
<< " | Partition = " << partition_data.dbus_path;
|
||||
QWriteLocker locker(&device_data_lock_);
|
||||
device_data_[partition_data.unique_id()] = partition_data;
|
||||
DeviceAdded(partition_data.unique_id());
|
||||
}
|
||||
|
||||
void Udisks2Lister::HandleFinishedUnmountJob(
|
||||
const Udisks2Lister::PartitionData& partition_data,
|
||||
const QDBusObjectPath& mounted_object) {
|
||||
QWriteLocker locker(&device_data_lock_);
|
||||
QString id;
|
||||
for (auto& data : device_data_) {
|
||||
if (data.mount_paths.contains(mounted_object.path())) {
|
||||
qLog(Debug)
|
||||
<< "UDisks2 umount job finished, found corresponding device: Drive = "
|
||||
<< data.dbus_drive_path << " | Partition = " << data.dbus_path;
|
||||
data.mount_paths.removeOne(mounted_object.path());
|
||||
if (data.mount_paths.empty()) id = data.unique_id();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id.isEmpty()) {
|
||||
qLog(Debug) << "Partition " << partition_data.dbus_path
|
||||
<< " has no more mount points, removing it from device list";
|
||||
device_data_.remove(id);
|
||||
DeviceRemoved(id);
|
||||
}
|
||||
}
|
||||
|
||||
Udisks2Lister::PartitionData Udisks2Lister::ReadPartitionData(
|
||||
const QDBusObjectPath& path) {
|
||||
PartitionData result;
|
||||
OrgFreedesktopUDisks2FilesystemInterface filesystem(
|
||||
udisks2_service_, path.path(), QDBusConnection::systemBus());
|
||||
OrgFreedesktopUDisks2BlockInterface block(udisks2_service_, path.path(),
|
||||
QDBusConnection::systemBus());
|
||||
|
||||
if (filesystem.isValid() && block.isValid() &&
|
||||
!filesystem.mountPoints().empty()) {
|
||||
OrgFreedesktopUDisks2DriveInterface drive(
|
||||
udisks2_service_, block.drive().path(), QDBusConnection::systemBus());
|
||||
|
||||
if (drive.isValid() && drive.mediaRemovable()) {
|
||||
result.dbus_path = path.path();
|
||||
result.dbus_drive_path = block.drive().path();
|
||||
|
||||
result.serial = drive.serial();
|
||||
result.vendor = drive.vendor();
|
||||
result.model = drive.model();
|
||||
|
||||
result.label = block.idLabel();
|
||||
result.uuid = block.idUUID();
|
||||
result.capacity = drive.size();
|
||||
|
||||
if (!result.label.isEmpty())
|
||||
result.friendly_name = result.label;
|
||||
else
|
||||
result.friendly_name = result.model + " " + result.uuid;
|
||||
|
||||
for (const auto& path : filesystem.mountPoints())
|
||||
result.mount_paths.push_back(path);
|
||||
|
||||
result.free_space =
|
||||
Utilities::FileSystemFreeSpace(result.mount_paths.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString Udisks2Lister::PartitionData::unique_id() const {
|
||||
return QString("Udisks2/%1/%2/%3/%4/%5")
|
||||
.arg(serial, vendor, model)
|
||||
.arg(capacity)
|
||||
.arg(uuid);
|
||||
}
|
119
src/devices/udisks2lister.h
Normal file
119
src/devices/udisks2lister.h
Normal file
@ -0,0 +1,119 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2016, Valeriy Malov <jazzvoid@gmail.com>
|
||||
|
||||
Clementine 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
|
||||
(at your option) any later version.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UDISKS2LISTER_H
|
||||
#define UDISKS2LISTER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QMutex>
|
||||
#include <QReadWriteLock>
|
||||
#include <QStringList>
|
||||
|
||||
#include "devicelister.h"
|
||||
#include "dbus/metatypes.h"
|
||||
|
||||
class OrgFreedesktopDBusObjectManagerInterface;
|
||||
class OrgFreedesktopUDisks2JobInterface;
|
||||
|
||||
class Udisks2Lister : public DeviceLister {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Udisks2Lister();
|
||||
~Udisks2Lister();
|
||||
|
||||
QStringList DeviceUniqueIDs() override;
|
||||
QVariantList DeviceIcons(const QString& id) override;
|
||||
QString DeviceManufacturer(const QString& id) override;
|
||||
QString DeviceModel(const QString& id) override;
|
||||
quint64 DeviceCapacity(const QString& id) override;
|
||||
quint64 DeviceFreeSpace(const QString& id) override;
|
||||
QVariantMap DeviceHardwareInfo(const QString& id) override;
|
||||
|
||||
QString MakeFriendlyName(const QString& id) override;
|
||||
QList<QUrl> MakeDeviceUrls(const QString& id) override;
|
||||
|
||||
void UnmountDevice(const QString& id) override;
|
||||
|
||||
public slots:
|
||||
void UpdateDeviceFreeSpace(const QString& id) override;
|
||||
|
||||
protected:
|
||||
void Init() override;
|
||||
|
||||
private slots:
|
||||
void DBusInterfaceAdded(const QDBusObjectPath& path,
|
||||
const InterfacesAndProperties& ifaces);
|
||||
void DBusInterfaceRemoved(const QDBusObjectPath& path,
|
||||
const QStringList& ifaces);
|
||||
void JobCompleted(bool success, const QString& message);
|
||||
|
||||
private:
|
||||
bool isPendingJob(const QDBusObjectPath& job_path);
|
||||
void RemoveDevice(const QDBusObjectPath& device_path);
|
||||
QList<QDBusObjectPath> GetMountedPartitionsFromDBusArgument(
|
||||
const QDBusArgument& input);
|
||||
|
||||
struct Udisks2Job {
|
||||
bool is_mount = true;
|
||||
QList<QDBusObjectPath> mounted_partitions;
|
||||
std::shared_ptr<OrgFreedesktopUDisks2JobInterface> dbus_interface;
|
||||
};
|
||||
|
||||
QMutex jobs_lock_;
|
||||
QMap<QDBusObjectPath, Udisks2Job> mounting_jobs_;
|
||||
|
||||
private:
|
||||
struct PartitionData {
|
||||
QString unique_id() const;
|
||||
|
||||
QString dbus_path;
|
||||
QString friendly_name;
|
||||
|
||||
// Device
|
||||
QString serial;
|
||||
QString vendor;
|
||||
QString model;
|
||||
quint64 capacity = 0;
|
||||
QString dbus_drive_path;
|
||||
|
||||
// Paritition
|
||||
QString label;
|
||||
QString uuid;
|
||||
quint64 free_space = 0;
|
||||
QStringList mount_paths;
|
||||
};
|
||||
|
||||
PartitionData ReadPartitionData(const QDBusObjectPath& path);
|
||||
void HandleFinishedMountJob(
|
||||
const Udisks2Lister::PartitionData& partition_data);
|
||||
void HandleFinishedUnmountJob(
|
||||
const Udisks2Lister::PartitionData& partition_data,
|
||||
const QDBusObjectPath& mounted_object);
|
||||
|
||||
QReadWriteLock device_data_lock_;
|
||||
QMap<QString, PartitionData> device_data_;
|
||||
|
||||
private:
|
||||
std::unique_ptr<OrgFreedesktopDBusObjectManagerInterface> udisks2_interface_;
|
||||
|
||||
static constexpr char udisks2_service_[] = "org.freedesktop.UDisks2";
|
||||
};
|
||||
|
||||
#endif // UDISKS2LISTER_H
|
Loading…
x
Reference in New Issue
Block a user