From 7dfe0ef09701d913d0b059647e42088e465fc7d8 Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Sat, 20 Jul 2019 15:16:36 +0800 Subject: [PATCH] basic volume and mount info support --- gio-qt/CMakeLists.txt | 2 + gio-qt/dgiofile.cpp | 96 ++++++++++++++++++++++++ gio-qt/dgiofile.h | 31 ++++++++ gio-qt/dgiomount.cpp | 137 ++++++++++++++++++++++++++++++----- gio-qt/dgiomount.h | 9 ++- gio-qt/dgiovolume.cpp | 55 +++++++++++++- gio-qt/dgiovolume.h | 20 ++++- gio-qt/dgiovolumemanager.cpp | 97 ++++++++++++++++++++++--- gio-qt/dgiovolumemanager.h | 13 ++-- qgio-tools/main.cpp | 57 +++++++++++++-- 10 files changed, 474 insertions(+), 43 deletions(-) create mode 100644 gio-qt/dgiofile.cpp create mode 100644 gio-qt/dgiofile.h diff --git a/gio-qt/CMakeLists.txt b/gio-qt/CMakeLists.txt index 6507491..042509f 100644 --- a/gio-qt/CMakeLists.txt +++ b/gio-qt/CMakeLists.txt @@ -4,12 +4,14 @@ set (QGIO_PUBLIC_HEADER_FILES dgiovolumemanager.h dgiomount.h dgiovolume.h + dgiofile.h ) set (QGIO_PRIVATE_CPP_FILES dgiovolumemanager.cpp dgiomount.cpp dgiovolume.cpp + dgiofile.cpp ) # Library diff --git a/gio-qt/dgiofile.cpp b/gio-qt/dgiofile.cpp new file mode 100644 index 0000000..f898bb6 --- /dev/null +++ b/gio-qt/dgiofile.cpp @@ -0,0 +1,96 @@ +#include "dgiofile.h" + +#include + +#include +#include + +using namespace Gio; + +class DGioFilePrivate +{ +public: + DGioFilePrivate(DGioFile *qq, File *gmmFilePtr); + + Glib::RefPtr getGmmFileInstance() const; + +private: + Glib::RefPtr m_gmmFilePtr; + + QString uri() const; + + DGioFile *q_ptr; + + Q_DECLARE_PUBLIC(DGioFile) +}; + +DGioFilePrivate::DGioFilePrivate(DGioFile *qq, File *gmmFilePtr) + : m_gmmFilePtr(gmmFilePtr) + , q_ptr(qq) +{ + +} + +Glib::RefPtr DGioFilePrivate::getGmmFileInstance() const +{ + return m_gmmFilePtr; +} + +QString DGioFilePrivate::uri() const +{ + return QString::fromStdString(m_gmmFilePtr->get_uri()); +} + +// ------------------------------------------------------------- + +DGioFile::DGioFile(File* gmmFilePtr, QObject *parent) + : QObject(parent) + , d_ptr(new DGioFilePrivate(this, gmmFilePtr)) +{ + // gmountPtr must be vaild; + Q_CHECK_PTR(gmmFilePtr); +} + +DGioFile::~DGioFile() +{ + +} + +/*! + * \brief Create a DGioFile instance by given \a path + * + * This operation never fails since Gio::File::create_for_path never fails, but the returned + * object might not support any I/O operation if path is malformed. + * + * \return the created DGioFile instance + */ +DGioFile *DGioFile::createFromPath(QString path, QObject *parent) +{ + // ensure GIO got initialized + Gio::init(); + + Glib::RefPtr gmmFile = File::create_for_path(path.toStdString()); + + return new DGioFile(gmmFile.release(), parent); +} + +QString DGioFile::basename() const +{ + Q_D(const DGioFile); + + return QString::fromStdString(d->getGmmFileInstance()->get_basename()); +} + +QString DGioFile::path() const +{ + Q_D(const DGioFile); + + return QString::fromStdString(d->getGmmFileInstance()->get_path()); +} + +QString DGioFile::uri() const +{ + Q_D(const DGioFile); + + return d->uri(); +} diff --git a/gio-qt/dgiofile.h b/gio-qt/dgiofile.h new file mode 100644 index 0000000..99e9bef --- /dev/null +++ b/gio-qt/dgiofile.h @@ -0,0 +1,31 @@ +#ifndef DGIOFILE_H +#define DGIOFILE_H + +#include +#include + +namespace Gio { +class File; +} + +class DGioFilePrivate; +class DGioFile : public QObject, public QSharedData +{ + Q_OBJECT +public: + explicit DGioFile(Gio::File *gmmFilePtr, QObject *parent = nullptr); + ~DGioFile(); + + static DGioFile * createFromPath(QString path, QObject *parent = nullptr); + + QString basename() const; + QString path() const; + QString uri() const; + +private: + QScopedPointer d_ptr; + + Q_DECLARE_PRIVATE(DGioFile) +}; + +#endif // DGIOFILE_H diff --git a/gio-qt/dgiomount.cpp b/gio-qt/dgiomount.cpp index e384269..9765a0e 100644 --- a/gio-qt/dgiomount.cpp +++ b/gio-qt/dgiomount.cpp @@ -1,7 +1,12 @@ #include "dgiomount.h" +#include "dgiovolume.h" #include + +#include #include +#include +#include #include @@ -10,9 +15,9 @@ using namespace Gio; class DGioMountPrivate { public: - DGioMountPrivate(DGioMount *qq, Mount *gmountPtr); + DGioMountPrivate(DGioMount *qq, Mount *gmmMountPtr); - Glib::RefPtr getGMountInstance() const; + Glib::RefPtr getGmmMountInstance() const; QString name() const; QString uuid() const; @@ -20,43 +25,43 @@ public: bool canEject() const; private: - Glib::RefPtr m_gmountPtr; + Glib::RefPtr m_gmmMountPtr; DGioMount *q_ptr; Q_DECLARE_PUBLIC(DGioMount) }; -DGioMountPrivate::DGioMountPrivate(DGioMount *qq, Mount *gmountPtr) - : m_gmountPtr(gmountPtr) +DGioMountPrivate::DGioMountPrivate(DGioMount *qq, Mount *gmmMountPtr) + : m_gmmMountPtr(gmmMountPtr) , q_ptr(qq) { } -Glib::RefPtr DGioMountPrivate::getGMountInstance() const +Glib::RefPtr DGioMountPrivate::getGmmMountInstance() const { - return m_gmountPtr; + return m_gmmMountPtr; } QString DGioMountPrivate::name() const { - return QString::fromStdString(m_gmountPtr->get_name()); + return QString::fromStdString(m_gmmMountPtr->get_name()); } QString DGioMountPrivate::uuid() const { - return QString::fromStdString(m_gmountPtr->get_uuid()); + return QString::fromStdString(m_gmmMountPtr->get_uuid()); } // ------------------------------------------------------------- -DGioMount::DGioMount(Mount* gmountPtr, QObject *parent) +DGioMount::DGioMount(Mount* gmmMountPtr, QObject *parent) : QObject(parent) - , d_ptr(new DGioMountPrivate(this, gmountPtr)) + , d_ptr(new DGioMountPrivate(this, gmmMountPtr)) { // gmountPtr must be vaild; - Q_CHECK_PTR(gmountPtr); + Q_CHECK_PTR(gmmMountPtr); } DGioMount::~DGioMount() @@ -64,13 +69,21 @@ DGioMount::~DGioMount() } +/*! + * \brief Create a DGioMount instance by a given \a path + * + * \return the created DGioMount instance or nullptr if failed. + */ DGioMount *DGioMount::createFromPath(QString path, QObject *parent) { - Glib::RefPtr gfile = File::create_for_path(path.toStdString()); + // ensure GIO got initialized + Gio::init(); + + Glib::RefPtr gmmFile = File::create_for_path(path.toStdString()); try { - Glib::RefPtr gmount = gfile->find_enclosing_mount(); - if (gmount) { - return new DGioMount(gmount.release(), parent); + Glib::RefPtr gmmMount = gmmFile->find_enclosing_mount(); + if (gmmMount) { + return new DGioMount(gmmMount.release(), parent); } } catch (Glib::Error error) { qDebug() << QString::fromStdString(error.what().raw()); @@ -93,17 +106,105 @@ QString DGioMount::uuid() const return d->uuid(); } +/*! + * \brief Determines if mount is shadowed. + * + * A mount is said to be shadowed if there exists one or more user visible objects (currently Mount objects) + * with a root that is inside the root of mount. + * + * One application of shadow mounts is when exposing a single file system that is used to address several + * logical volumes. In this situation, a Gio::VolumeMonitor implementation would create two Gio::Volume + * objects, in gio-qt, DGioVolumeManager will create two DGioVolume objects. + * + * For example, one for the camera functionality of the device and one for a SD card reader on the device) with + * activation URIs gphoto2://[usb:001,002]/store1/ and gphoto2://[usb:001,002]/store2/. When the underlying + * mount (with root gphoto2://[usb:001,002]/) is mounted, said VolumeMonitor implementation would create two + * Mount objects (each with their root matching the corresponding volume activation root) that would shadow + * the original mount. + * + * \return true if mount is shadowed + */ +bool DGioMount::isShadowed() const +{ + Q_D(const DGioMount); + + return d->getGmmMountInstance()->is_shadowed(); +} + bool DGioMount::canUnmount() const { Q_D(const DGioMount); - return d->getGMountInstance()->can_unmount(); + return d->getGmmMountInstance()->can_unmount(); } bool DGioMount::canEject() const { Q_D(const DGioMount); - return d->getGMountInstance()->can_eject(); + return d->getGmmMountInstance()->can_eject(); +} + +QStringList DGioMount::themedIconNames() const +{ + Q_D(const DGioMount); + + QStringList iconNames; + + Glib::RefPtr icon = d->getGmmMountInstance()->get_icon(); + Glib::RefPtr themedIcon = Glib::RefPtr::cast_dynamic(icon); + +// if (G_IS_THEMED_ICON(themedIcon->gobj()) ) { +// qDebug() << "Yes and"; +// } + +// if (themedIcon) { +// qDebug() << "Yes"; +// } + + if (themedIcon) { + QStringList iconNames; + char **names; + char **iter; + names = NULL; + g_object_get(G_THEMED_ICON(themedIcon->gobj()), "names", &names, NULL); + for (iter = names; *iter; iter++) { + iconNames.append(QString(*iter)); + } + g_strfreev(names); + return iconNames; + } + +// return {QStringList::fromStdList(themedIcon->get_names())}; + +// char* name = 0; +// g_object_get(G_OBJECT(themedIcon->gobj()), "name", &name, NULL); +// return {QString(name)}; + +// if (themedIcon) { +// auto ustring_names = themedIcon->get_names(); +//// for (const Glib::ustring &str : ustring_names) { +//// iconNames.append(QString::fromStdString(str.raw())); +//// } +// } + + return iconNames; +} + +void DGioMount::unmount(bool forceUnmount) +{ + Q_D(const DGioMount); + + return d->getGmmMountInstance()->unmount(forceUnmount ? MOUNT_UNMOUNT_FORCE : MOUNT_UNMOUNT_NONE); +} + +QExplicitlySharedDataPointer DGioMount::getVolume() +{ + Q_D(const DGioMount); + + Glib::RefPtr vol = d->getGmmMountInstance()->get_volume(); + QExplicitlySharedDataPointer volPtr(new DGioVolume(vol.release())); + + return volPtr; } diff --git a/gio-qt/dgiomount.h b/gio-qt/dgiomount.h index 025c0ee..1157809 100644 --- a/gio-qt/dgiomount.h +++ b/gio-qt/dgiomount.h @@ -8,20 +8,27 @@ namespace Gio { class Mount; } +class DGioVolume; class DGioMountPrivate; class DGioMount : public QObject, public QSharedData { Q_OBJECT public: - explicit DGioMount(Gio::Mount *gmountPtr, QObject *parent = nullptr); + explicit DGioMount(Gio::Mount *gmmMountPtr, QObject *parent = nullptr); ~DGioMount(); static DGioMount * createFromPath(QString path, QObject *parent = nullptr); QString name() const; QString uuid() const; + bool isShadowed() const; bool canUnmount() const; bool canEject() const; + QStringList themedIconNames() const; + + void unmount(bool forceUnmount = false); + + QExplicitlySharedDataPointer getVolume(); private: QScopedPointer d_ptr; diff --git a/gio-qt/dgiovolume.cpp b/gio-qt/dgiovolume.cpp index 0c2fd53..a156cbf 100644 --- a/gio-qt/dgiovolume.cpp +++ b/gio-qt/dgiovolume.cpp @@ -1,6 +1,59 @@ #include "dgiovolume.h" -DGioVolume::DGioVolume() +#include +#include + +#include + +using namespace Gio; + +class DGioVolumePrivate +{ +public: + DGioVolumePrivate(DGioVolume *qq, Volume *gmmVolumePtr); + + Glib::RefPtr getGmmVolumeInstance() const; + + QString name() const; + +private: + Glib::RefPtr m_gmmVolumePtr; + + DGioVolume *q_ptr; + + Q_DECLARE_PUBLIC(DGioVolume) +}; + +DGioVolumePrivate::DGioVolumePrivate(DGioVolume *qq, Volume *gmmVolumePtr) + : m_gmmVolumePtr(gmmVolumePtr) + , q_ptr(qq) +{ +// m_gvolumePtr = Glib::wrap(gvolumePtr); +} + +QString DGioVolumePrivate::name() const +{ + return QString::fromStdString(m_gmmVolumePtr->get_name()); +} + +// ------------------------------------------------------------- + +DGioVolume::DGioVolume(Volume* gmmVolumePtr, QObject *parent) + : QObject(parent) + , d_ptr(new DGioVolumePrivate(this, gmmVolumePtr)) +{ + // gvolumePtr must be vaild; + Q_CHECK_PTR(gmmVolumePtr); +} + +DGioVolume::~DGioVolume() { } + +QString DGioVolume::name() const +{ + Q_D(const DGioVolume); + + return d->name(); +} diff --git a/gio-qt/dgiovolume.h b/gio-qt/dgiovolume.h index 088b8b5..cae99a9 100644 --- a/gio-qt/dgiovolume.h +++ b/gio-qt/dgiovolume.h @@ -1,11 +1,27 @@ #ifndef DGIOVOLUME_H #define DGIOVOLUME_H +#include +#include -class DGioVolume +namespace Gio { +class Volume; +} + +class DGioVolumePrivate; +class DGioVolume : public QObject, public QSharedData { + Q_OBJECT public: - DGioVolume(); + explicit DGioVolume(Gio::Volume *gmmVolumePtr, QObject *parent = nullptr); + ~DGioVolume(); + + QString name() const; + +private: + QScopedPointer d_ptr; + + Q_DECLARE_PRIVATE(DGioVolume) }; #endif // DGIOVOLUME_H diff --git a/gio-qt/dgiovolumemanager.cpp b/gio-qt/dgiovolumemanager.cpp index e8f3e37..3f94f12 100644 --- a/gio-qt/dgiovolumemanager.cpp +++ b/gio-qt/dgiovolumemanager.cpp @@ -1,10 +1,10 @@ #include "dgiomount.h" +#include "dgiovolume.h" #include "dgiovolumemanager.h" -#include -#include - #include + +#include #include using namespace Gio; @@ -14,15 +14,75 @@ class DGioVolumeManagerPrivate DGioVolumeManagerPrivate(DGioVolumeManager *qq); private: + Glib::RefPtr m_gmmVolumeMonitorPtr; + DGioVolumeManager *q_ptr; + void slot_mountAdded(const Glib::RefPtr< Mount >& gmmMount); + void slot_mountRemoved(const Glib::RefPtr< Mount >& gmmMount); + void slot_mountPreRemoved(const Glib::RefPtr< Mount >& gmmMount); + void slot_mountChanged(const Glib::RefPtr< Mount >& gmmMount); + Q_DECLARE_PUBLIC(DGioVolumeManager) }; DGioVolumeManagerPrivate::DGioVolumeManagerPrivate(DGioVolumeManager *qq) : q_ptr(qq) { + // Do Gio's init or things like Gio::VolumeMonitor::get() won't working + // Gio::init() will also call Glib::init() so we don't need to call it again. + Gio::init(); + m_gmmVolumeMonitorPtr = VolumeMonitor::get(); + + m_gmmVolumeMonitorPtr->signal_mount_added().connect(sigc::mem_fun(*this, &DGioVolumeManagerPrivate::slot_mountAdded)); + m_gmmVolumeMonitorPtr->signal_mount_removed().connect(sigc::mem_fun(*this, &DGioVolumeManagerPrivate::slot_mountRemoved)); + m_gmmVolumeMonitorPtr->signal_mount_pre_unmount().connect(sigc::mem_fun(*this, &DGioVolumeManagerPrivate::slot_mountPreRemoved)); + m_gmmVolumeMonitorPtr->signal_mount_changed().connect(sigc::mem_fun(*this, &DGioVolumeManagerPrivate::slot_mountChanged)); +} + +void DGioVolumeManagerPrivate::slot_mountAdded(const Glib::RefPtr &gmmMount) +{ + Q_Q(DGioVolumeManager); + + Glib::RefPtr copy(gmmMount); + + QExplicitlySharedDataPointer mount(new DGioMount(copy.release())); + + Q_EMIT q->mountAdded(mount); +} + +void DGioVolumeManagerPrivate::slot_mountRemoved(const Glib::RefPtr &gmmMount) +{ + Q_Q(DGioVolumeManager); + + Glib::RefPtr copy(gmmMount); + + QExplicitlySharedDataPointer mount(new DGioMount(copy.release())); + + Q_EMIT q->mountRemoved(mount); +} + +void DGioVolumeManagerPrivate::slot_mountPreRemoved(const Glib::RefPtr &gmmMount) +{ + Q_Q(DGioVolumeManager); + + Glib::RefPtr copy(gmmMount); + + QExplicitlySharedDataPointer mount(new DGioMount(copy.release())); + + Q_EMIT q->mountPreRemoved(mount); +} + +void DGioVolumeManagerPrivate::slot_mountChanged(const Glib::RefPtr &gmmMount) +{ + Q_Q(DGioVolumeManager); + + Glib::RefPtr copy(gmmMount); + + QExplicitlySharedDataPointer mount(new DGioMount(copy.release())); + + Q_EMIT q->mountChanged(mount); } @@ -30,24 +90,24 @@ DGioVolumeManager::DGioVolumeManager(QObject *parent) : QObject(parent) , d_ptr(new DGioVolumeManagerPrivate(this)) { - // Do Gio's init or things like Gio::VolumeMonitor::get() won't working - // can we init it multiple times? - Glib::init(); - Gio::init(); + } DGioVolumeManager::~DGioVolumeManager() { - // + } const QList > DGioVolumeManager::getMounts() { + // ensure GIO got initialized + Gio::init(); + QList > mounts; Glib::RefPtr vm = Gio::VolumeMonitor::get(); - Glib::ListHandle> mnt = vm->get_mounts(); + Glib::ListHandle > mnt = vm->get_mounts(); for (Glib::RefPtr oneMnt : mnt) { QExplicitlySharedDataPointer mntPtr(new DGioMount(oneMnt.release())); @@ -56,3 +116,22 @@ const QList > DGioVolumeManager::getMoun return mounts; } + +const QList > DGioVolumeManager::getVolumes() +{ + // ensure GIO got initialized + Gio::init(); + + QList > volumes; + + Glib::RefPtr vm = Gio::VolumeMonitor::get(); + + Glib::ListHandle > vol = vm->get_volumes(); + for (Glib::RefPtr oneVol : vol) { + + QExplicitlySharedDataPointer volPtr(new DGioVolume(oneVol.release())); + volumes.append(volPtr); + } + + return volumes; +} diff --git a/gio-qt/dgiovolumemanager.h b/gio-qt/dgiovolumemanager.h index 56a012f..2898fcf 100644 --- a/gio-qt/dgiovolumemanager.h +++ b/gio-qt/dgiovolumemanager.h @@ -4,10 +4,6 @@ #include #include -namespace Gio { -class Mount; -} - class DGioMount; class DGioVolume; class DGioVolumeManagerPrivate; @@ -18,7 +14,14 @@ public: explicit DGioVolumeManager(QObject *parent = nullptr); ~DGioVolumeManager(); - const QList > getMounts(); + static const QList > getMounts(); + static const QList > getVolumes(); + +Q_SIGNALS: + void mountAdded(QExplicitlySharedDataPointer mount); + void mountRemoved(QExplicitlySharedDataPointer mount); + void mountPreRemoved(QExplicitlySharedDataPointer mount); + void mountChanged(QExplicitlySharedDataPointer mount); private: QScopedPointer d_ptr; diff --git a/qgio-tools/main.cpp b/qgio-tools/main.cpp index dea2481..5c696dc 100644 --- a/qgio-tools/main.cpp +++ b/qgio-tools/main.cpp @@ -1,22 +1,65 @@ #include +#include #include +#include #include +#include #include -int main() +int main(int argc, char * argv[]) { DGioMount * m = DGioMount::createFromPath("/media/wzc/aaaaaaaaaaaaaaaa"); if (m) { - qDebug() << m->name(); + qDebug() << m->name() << m->themedIconNames(); + delete m; } - DGioVolumeManager mgr; - const QList > lst = mgr.getMounts(); - - for (const QExplicitlySharedDataPointer &p : lst) { - qDebug() << p->name() << m->uuid() << m->canUnmount(); + DGioFile * f = DGioFile::createFromPath("/media/wzc/aaaaaaaaaaaaaaaa"); + if (f) { + qDebug() << f->basename() << f->path() << f->uri(); + delete f; } + qDebug() << "----------------------"; + + const QList > mnts = DGioVolumeManager::getMounts(); + + for (const QExplicitlySharedDataPointer &p : mnts) { + qDebug() << p->name() << p->uuid() << p->canUnmount() << p->themedIconNames() << p->themedIconNames(); + } + + qDebug() << "----------------------"; + + const QList > vols = DGioVolumeManager::getVolumes(); + + for (const QExplicitlySharedDataPointer &p : vols) { + qDebug() << p->name(); + } + + qDebug() << "----------------------"; + + QCoreApplication app(argc, argv); + + DGioVolumeManager vm; + + QObject::connect(&vm, &DGioVolumeManager::mountAdded, [](QExplicitlySharedDataPointer mnt){ + qDebug() << "MountAdded" << mnt->name(); + }); + + QObject::connect(&vm, &DGioVolumeManager::mountPreRemoved, [](QExplicitlySharedDataPointer mnt){ + qDebug() << "MountPreRemoved" << mnt->name(); + }); + + QObject::connect(&vm, &DGioVolumeManager::mountRemoved, [](QExplicitlySharedDataPointer mnt){ + qDebug() << "MountRemoved" << mnt->name(); + }); + + QObject::connect(&vm, &DGioVolumeManager::mountChanged, [](QExplicitlySharedDataPointer mnt){ + qDebug() << "MountChanged" << mnt->name(); + }); + + app.exec(); + return 0; }