Display which process blocks unmount/eject in a plasmoid notification

REVIEW: 125248
BUG: 96107
wilder-5.14
Igor Poboiko 11 years ago
parent 8b9af71063
commit d64719de4b
  1. 1
      dataengines/devicenotifications/CMakeLists.txt
  2. 78
      dataengines/devicenotifications/ksolidnotify.cpp
  3. 2
      dataengines/devicenotifications/ksolidnotify.h

@ -12,6 +12,7 @@ target_link_libraries(plasma_engine_devicenotifications
KF5::Plasma
KF5::Solid
KF5::I18n
KF5::ProcessCore
) # todo: add kworkspace once ported
kcoreaddons_desktop_to_json(plasma_engine_devicenotifications plasma-dataengine-devicenotifications.desktop)

@ -31,6 +31,11 @@
#include <Solid/Predicate>
#include <KLocalizedString>
#include <processcore/process.h>
#include <processcore/processes.h>
#include <QStringList>
#include <QProcess>
KSolidNotify::KSolidNotify(QObject* parent):
QObject(parent)
@ -113,12 +118,60 @@ void KSolidNotify::storageSetupDone(Solid::ErrorType error, QVariant errorData,
}
}
void KSolidNotify::queryBlockingApps(const QString &devicePath)
{
QProcess *p = new QProcess;
connect(p, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), [=](QProcess::ProcessError) {
emit blockingAppsReady({});
p->deleteLater();
});
connect(p, static_cast<void (QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), [=](int,QProcess::ExitStatus) {
QStringList blockApps;
QString out(p->readAll());
const QStringList &pidList = out.split(QRegExp("\\s+"), QString::SkipEmptyParts);
KSysGuard::Processes procs;
Q_FOREACH (const QString &pidStr, pidList) {
int pid = pidStr.toInt();
if (!pid) {
continue;
}
procs.updateOrAddProcess(pid);
KSysGuard::Process *proc = procs.getProcess(pid);
if (!blockApps.contains(proc->name())) {
blockApps << proc->name();
}
}
blockApps.removeDuplicates();
emit blockingAppsReady(blockApps);
p->deleteLater();
});
p->start(QStringLiteral("lsof"), {QStringLiteral("-t"), devicePath});
// p.start(QStringLiteral("fuser"), {QStringLiteral("-m"), devicePath});
}
void KSolidNotify::storageTeardownDone(Solid::ErrorType error, QVariant errorData, const QString &udi)
{
if (error) {
Solid::Device device(udi);
const QString errorMessage = i18n("Could not unmount the following device: %1\nOne or more files on this device are open within an application ", device.description());
emit notify(error, errorMessage, errorData.toString(), udi);
Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
// Without that, our lambda function would capture an uninitialized object, resulting in UB
// and random crashes
QMetaObject::Connection *c = new QMetaObject::Connection();
*c = connect(this, &KSolidNotify::blockingAppsReady,
[=] (const QStringList &blockApps) {
QString errorMessage;
if (blockApps.isEmpty()) {
errorMessage = i18n("Could not safely remove the following device: %1\nOne or more files on this device are open within an application", device.description());
} else {
errorMessage = i18np("Could not safely remove the following device: %1\nOne or more files on this device are opened in application \"%3\"\nPlease close it and try again",
"Could not safely remove the following device: %1\nOne or more files on this device are opened in following applications: %3\nPlease close it and try again",
device.description(), blockApps.size(), blockApps.join(i18nc("separator in list of apps blocking device unmount", ", ")));
}
emit notify(error, errorMessage, errorData.toString(), udi);
disconnect(*c);
delete c;
});
queryBlockingApps(access->filePath());
} else if (isSafelyRemovable(udi)) {
Solid::Device device(udi);
const QString errorMessage = i18nc("The term \"remove\" here means \"physically disconnect the device from the computer\", whereas \"safely\" means \"without risk of data loss\"", "The following device can now be safely removed: %1", device.description());
@ -143,8 +196,25 @@ void KSolidNotify::storageEjectDone(Solid::ErrorType error, QVariant errorData,
}
Solid::Device discDevice(discUdi);
const QString errorMessage = i18n("Could not eject the following device: %1\nOne or more files on this device are open within an application ", discDevice.description());
emit notify(error, errorMessage, errorData.toString(), udi);
Solid::StorageAccess *access = discDevice.as<Solid::StorageAccess>();
// Without that, our lambda function would capture an uninitialized object, resulting in UB
// and random crashes
QMetaObject::Connection *c = new QMetaObject::Connection();
*c = connect(this, &KSolidNotify::blockingAppsReady,
[=] (const QStringList &blockApps) {
QString errorMessage;
if (blockApps.isEmpty()) {
errorMessage = i18n("Could not eject the following device: %1\nOne or more files on this device are open within an application", discDevice.description());
} else {
errorMessage = i18np("Could not eject the following device: %1\nOne or more files on this device are opened in application \"%3\"\nPlease close it and try again",
"Could not eject the following device: %1\nOne or more files on this device are opened in following applications: %3\nPlease close it and try again",
discDevice.description(), blockApps.size(), blockApps.join(i18nc("separator in list of apps blocking device unmount", ", ")));
}
emit notify(error, errorMessage, errorData.toString(), udi);
disconnect(*c);
delete c;
});
queryBlockingApps(access->filePath());
} else if (isSafelyRemovable(udi)) {
Solid::Device device(udi);
const QString errorMessage = i18n("The following device can now be safely removed: %1", device.description());

@ -47,6 +47,7 @@ public:
signals:
void notify(Solid::ErrorType solidError, const QString& error, const QString& errorDetails, const QString &udi);
void blockingAppsReady(const QStringList &apps);
protected slots:
void onDeviceAdded(const QString &udi);
@ -60,6 +61,7 @@ private slots:
private:
void connectSignals(Solid::Device* device);
bool isSafelyRemovable(const QString &udi);
void queryBlockingApps(const QString &devicePath);
QHash<QString, Solid::Device> m_devices;
};

Loading…
Cancel
Save