diff --git a/.gitignore b/.gitignore index 886b175..e551b84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /kdelibs-4.8.5.tar.xz /kdelibs-4.9.3.tar.xz +/kdelibs-4.9.4.tar.xz diff --git a/0001-Fix-crash-when-no-service-was-selected-user-clicked-.patch b/0001-Fix-crash-when-no-service-was-selected-user-clicked-.patch new file mode 100644 index 0000000..a3e4f8e --- /dev/null +++ b/0001-Fix-crash-when-no-service-was-selected-user-clicked-.patch @@ -0,0 +1,25 @@ +From 0820b3173aff4f0f3c803a9e75e726024da38ee5 Mon Sep 17 00:00:00 2001 +From: David Faure +Date: Thu, 6 Dec 2012 11:55:05 +0100 +Subject: [PATCH] Fix crash when no service was selected (user clicked on + "Open With...") + +--- + kparts/browserrun.cpp | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/kparts/browserrun.cpp b/kparts/browserrun.cpp +index 6d84800..6de0380 100644 +--- a/kparts/browserrun.cpp ++++ b/kparts/browserrun.cpp +@@ -304,7 +304,7 @@ BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString& _ + this, SLOT(slotCopyToTempFileResult(KJob*)) ); + return Delayed; // We'll continue after the job has finished + } +- if (selectedService) { ++ if (selectedService && question.selectedService()) { + *selectedService = question.selectedService(); + // KRun will use this when starting an app + KRun::setPreferredService(question.selectedService()->desktopEntryName()); +-- +1.7.7 diff --git a/0001-Revert-Also-check-parent-mimetypes-in-protocolForArc.patch b/0001-Revert-Also-check-parent-mimetypes-in-protocolForArc.patch new file mode 100644 index 0000000..5aadeb8 --- /dev/null +++ b/0001-Revert-Also-check-parent-mimetypes-in-protocolForArc.patch @@ -0,0 +1,53 @@ +From 73283f1332e90fbb6fe0caa39a038cb16b83a54c Mon Sep 17 00:00:00 2001 +From: David Faure +Date: Wed, 5 Dec 2012 22:42:25 +0100 +Subject: [PATCH] Revert "Also check parent mimetypes in + protocolForArchiveMimetype()." + +This reverts commit 4f296cfbced2c4ad54beec8f500ed2d3fc04ee05. +It breaks opening odt and other zip-based files in external apps. +That's what I get for delegating the testing :-) +BUG: 311214 +--- + kio/kio/kprotocolmanager.cpp | 19 +------------------ + 1 files changed, 1 insertions(+), 18 deletions(-) + +diff --git a/kio/kio/kprotocolmanager.cpp b/kio/kio/kprotocolmanager.cpp +index 3f1cadd..502a3e6 100644 +--- a/kio/kio/kprotocolmanager.cpp ++++ b/kio/kio/kprotocolmanager.cpp +@@ -47,7 +47,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -1190,23 +1189,7 @@ QString KProtocolManager::protocolForArchiveMimetype( const QString& mimeType ) + } + } + } +- const QString prot = d->protocolForArchiveMimetypes.value(mimeType); +- if (!prot.isEmpty()) +- return prot; +- +- // Check parent mimetypes +- KMimeType::Ptr mime = KMimeType::mimeType(mimeType); +- if (mime) { +- const QStringList parentMimeTypes = mime->allParentMimeTypes(); +- Q_FOREACH(const QString& parentMimeType, parentMimeTypes) { +- const QString res = d->protocolForArchiveMimetypes.value(parentMimeType); +- if (!res.isEmpty()) { +- return res; +- } +- } +- } +- +- return QString(); ++ return d->protocolForArchiveMimetypes.value(mimeType); + } + + #undef PRIVATE_DATA +-- +1.7.7 diff --git a/kdelibs-4.9.3-delete-downloadDialog.patch b/kdelibs-4.9.3-delete-downloadDialog.patch deleted file mode 100644 index 4e0387b..0000000 --- a/kdelibs-4.9.3-delete-downloadDialog.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- kdelibs-4.9.3/plasma/private/packages.cpp 2012-10-19 12:26:32.000000000 +0200 -+++ kdelibs-4.9.3/plasma/private/packages.cpp_new 2012-11-23 13:19:25.757302077 +0100 -@@ -109,6 +109,7 @@ void PlasmoidPackage::createNewWidgetBro - m_knsDialog = knsDialog = new KNS3::DownloadDialog("plasmoids.knsrc", parent); - knsDialog->setProperty("DoNotCloseController", true); - connect(knsDialog, SIGNAL(accepted()), this, SIGNAL(newWidgetBrowserFinished())); -+ connect(knsDialog, SIGNAL(accepted()), knsDialog, SLOT(deleteLater())); - } - - knsDialog->show(); diff --git a/kdelibs-4.9.3-dot.patch b/kdelibs-4.9.3-dot.patch new file mode 100644 index 0000000..2bca78d --- /dev/null +++ b/kdelibs-4.9.3-dot.patch @@ -0,0 +1,12 @@ +diff -up kdelibs-4.9.3/doc/common/Doxyfile.global.me kdelibs-4.9.3/doc/common/Doxyfile.global +--- kdelibs-4.9.3/doc/common/Doxyfile.global.me 2012-12-04 16:57:09.239184154 +0100 ++++ kdelibs-4.9.3/doc/common/Doxyfile.global 2012-12-04 16:57:13.157191451 +0100 +@@ -1392,7 +1392,7 @@ HIDE_UNDOC_RELATIONS = NO + # toolkit from AT&T and Lucent Bell Labs. The other options in this section + # have no effect if this option is set to NO (the default) + +-HAVE_DOT = YES ++HAVE_DOT = NO + + # By default doxygen will write a font called FreeSans.ttf to the output + # directory and reference it in all dot files that doxygen generates. This diff --git a/kdelibs-4.9.3-kcm_ssl.patch b/kdelibs-4.9.3-kcm_ssl.patch new file mode 100644 index 0000000..b0d3f44 --- /dev/null +++ b/kdelibs-4.9.3-kcm_ssl.patch @@ -0,0 +1,12 @@ +diff -up kdelibs-4.9.3/kio/kssl/kcm/cacertificatespage.cpp.orig kdelibs-4.9.3/kio/kssl/kcm/cacertificatespage.cpp +--- kdelibs-4.9.3/kio/kssl/kcm/cacertificatespage.cpp.orig 2012-11-29 15:37:07.458858688 +0100 ++++ kdelibs-4.9.3/kio/kssl/kcm/cacertificatespage.cpp 2012-11-29 13:52:05.243926802 +0100 +@@ -291,7 +291,7 @@ void CaCertificatesPage::removeSelection + void CaCertificatesPage::addCertificateClicked() + { + QStringList certFiles +- = KFileDialog::getOpenFileNames(KUrl(), QLatin1String("application/x-x509-ca-cert"), ++ = KFileDialog::getOpenFileNames(KUrl(), QLatin1String("*.pem *.cert *.crt *.der"), + this, i18n("Pick Certificates")); + + QList certs; diff --git a/kdelibs-udisks2-backend.patch b/kdelibs-udisks2-backend.patch index c7c9a65..9ab0ac4 100644 --- a/kdelibs-udisks2-backend.patch +++ b/kdelibs-udisks2-backend.patch @@ -1,5 +1,5 @@ diff --git a/solid/solid/CMakeLists.txt b/solid/solid/CMakeLists.txt -index 0aa7a43..21e774c 100644 +index 0aa7a43..b00e50a 100644 --- a/solid/solid/CMakeLists.txt +++ b/solid/solid/CMakeLists.txt @@ -1,6 +1,7 @@ @@ -52,7 +52,7 @@ index 0aa7a43..21e774c 100644 message(STATUS "Building Solid UPower backend." ) set(solid_LIB_SRCS ${solid_LIB_SRCS} backends/upower/upowermanager.cpp -@@ -264,19 +237,19 @@ if(NOT WIN32 AND NOT APPLE) +@@ -264,19 +237,39 @@ if(NOT WIN32 AND NOT APPLE) # FIXME: this should work on more Unix systems if (CMAKE_SYSTEM_NAME MATCHES Linux) @@ -69,10 +69,14 @@ index 0aa7a43..21e774c 100644 - backends/udisks/udisksstorageaccess.cpp - backends/udisks/udisksgenericinterface.cpp - ) ++ ++ if ( WITH_SOLID_UDISKS2 ) + message(STATUS "Building Solid UDisks2 backend." ) ++ add_definitions(-DWITH_SOLID_UDISKS2) + set(solid_LIB_SRCS ${solid_LIB_SRCS} + backends/udisks2/udisksmanager.cpp + backends/udisks2/udisksdevice.cpp ++ backends/udisks2/udisksdevicebackend.cpp + backends/udisks2/udisksblock.cpp + backends/udisks2/udisksstoragevolume.cpp + backends/udisks2/udisksdeviceinterface.cpp @@ -81,7 +85,23 @@ index 0aa7a43..21e774c 100644 + backends/udisks2/udisksstoragedrive.cpp + backends/udisks2/udisksstorageaccess.cpp + backends/udisks2/udisksgenericinterface.cpp -+ backends/udisks2/dbus/manager.cpp) ++ backends/udisks2/dbus/manager.cpp ++ ) ++ else ( WITH_SOLID_UDISKS2 ) ++ message(STATUS "Building Solid UDisks backend." ) ++ set(solid_LIB_SRCS ${solid_LIB_SRCS} ++ backends/udisks/udisksmanager.cpp ++ backends/udisks/udisksdevice.cpp ++ backends/udisks/udisksblock.cpp ++ backends/udisks/udisksstoragevolume.cpp ++ backends/udisks/udisksdeviceinterface.cpp ++ backends/udisks/udisksopticaldisc.cpp ++ backends/udisks/udisksopticaldrive.cpp ++ backends/udisks/udisksstoragedrive.cpp ++ backends/udisks/udisksstorageaccess.cpp ++ backends/udisks/udisksgenericinterface.cpp ++ ) ++ endif ( WITH_SOLID_UDISKS2 ) endif (CMAKE_SYSTEM_NAME MATCHES Linux) message(STATUS "Building Solid fstab backend." ) @@ -451,10 +471,10 @@ index 0000000..19cb70a +#endif // UDISKS2BLOCK_H diff --git a/solid/solid/backends/udisks2/udisksdevice.cpp b/solid/solid/backends/udisks2/udisksdevice.cpp new file mode 100644 -index 0000000..a3f780f +index 0000000..2a4313a --- /dev/null +++ b/solid/solid/backends/udisks2/udisksdevice.cpp -@@ -0,0 +1,927 @@ +@@ -0,0 +1,833 @@ +/* + Copyright 2010 Michael Zanetti + Copyright 2010-2012 Lukáš Tinkl @@ -477,6 +497,7 @@ index 0000000..a3f780f +*/ + +#include "udisksdevice.h" ++#include "udisksdevicebackend.h" +#include "udisksblock.h" +#include "udisksdeviceinterface.h" +#include "udisksstoragevolume.h" @@ -548,28 +569,72 @@ index 0000000..a3f780f + +Device::Device(const QString &udi) + : Solid::Ifaces::Device() -+ , m_udi(udi) ++ , m_backend(DeviceBackend::backendForUDI(udi)) +{ -+ m_device = new QDBusInterface(UD2_DBUS_SERVICE, m_udi, -+ QString(), // no interface, we aggregate them -+ QDBusConnection::systemBus()); -+ -+ if (m_device->isValid()) { -+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, m_udi, DBUS_INTERFACE_PROPS, "PropertiesChanged", this, -+ SLOT(slotPropertiesChanged(QString,QVariantMap,QStringList))); -+ -+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, UD2_DBUS_PATH, DBUS_INTERFACE_MANAGER, "InterfacesAdded", -+ this, SLOT(slotInterfacesAdded(QDBusObjectPath,QVariantMapMap))); -+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, UD2_DBUS_PATH, DBUS_INTERFACE_MANAGER, "InterfacesRemoved", -+ this, SLOT(slotInterfacesRemoved(QDBusObjectPath,QStringList))); -+ -+ initInterfaces(); ++ if (m_backend) { ++ connect(m_backend, SIGNAL(changed()), this, SIGNAL(changed())); ++ connect(m_backend, SIGNAL(propertyChanged(QMap)), this, SIGNAL(propertyChanged(QMap))); ++ } else { ++ qDebug() << "Created invalid Device for udi" << udi; + } +} + +Device::~Device() +{ -+ delete m_device; ++} ++ ++QString Device::udi() const ++{ ++ if (m_backend) { ++ return m_backend->udi(); ++ } ++ ++ return QString(); ++} ++ ++QVariant Device::prop(const QString &key) const ++{ ++ if (m_backend) { ++ return m_backend->prop(key); ++ } ++ ++ return QVariant(); ++} ++ ++bool Device::propertyExists(const QString &key) const ++{ ++ if (m_backend) { ++ return m_backend->propertyExists(key); ++ } ++ ++ return false; ++} ++ ++QVariantMap Device::allProperties() const ++{ ++ if (m_backend) { ++ return m_backend->allProperties(); ++ } ++ ++ return QVariantMap(); ++} ++ ++bool Device::hasInterface(const QString &name) const ++{ ++ if (m_backend) { ++ return m_backend->interfaces().contains(name); ++ } ++ ++ return false; ++} ++ ++QStringList Device::interfaces() const ++{ ++ if (m_backend) { ++ return m_backend->interfaces(); ++ } ++ ++ return QStringList(); +} + +QObject* Device::createDeviceInterface(const Solid::DeviceInterface::Type& type) @@ -950,9 +1015,9 @@ index 0000000..a3f780f + if (isEncryptedContainer()) + { + if (!size_str.isEmpty()) -+ description = QCoreApplication::translate("", "%1 Encrypted Container", "%1 is the size").arg(size_str); ++ description = QCoreApplication::translate("", "%1 Encrypted Drive", "%1 is the size").arg(size_str); + else -+ description = QCoreApplication::translate("", "Encrypted Container"); ++ description = QCoreApplication::translate("", "Encrypted Drive"); + } + else if (drive_type == Solid::StorageDrive::HardDisk && !drive_is_removable) + { @@ -1075,35 +1140,29 @@ index 0000000..a3f780f + +QString Device::product() const +{ -+ QString product = prop("Model").toString(); -+ + if (!isDrive()) { -+ QString label = prop("IdLabel").toString(); -+ if (!label.isEmpty()) { -+ product = label; -+ } ++ Device drive(drivePath()); ++ return drive.prop("Model").toString(); + } + -+ return product; ++ return prop("Model").toString(); +} + +QString Device::vendor() const +{ -+ return prop("Vendor").toString(); -+} ++ if (!isDrive()) { ++ Device drive(drivePath()); ++ return drive.prop("Vendor").toString(); ++ } + -+QString Device::udi() const -+{ -+ return m_udi; ++ return prop("Vendor").toString(); +} + +QString Device::parentUdi() const +{ + QString parent; + -+ if (isEncryptedContainer()) -+ parent = prop("CryptoBackingDevice").value().path(); -+ else if (propertyExists("Drive")) // block ++ if (propertyExists("Drive")) // block + parent = prop("Drive").value().path(); + else if (propertyExists("Table")) // partition + parent = prop("Table").value().path(); @@ -1113,139 +1172,6 @@ index 0000000..a3f780f + return parent; +} + -+void Device::checkCache(const QString &key) const -+{ -+ if (m_cache.isEmpty()) // recreate the cache -+ allProperties(); -+ -+ if (m_cache.contains(key)) -+ return; -+ -+ QVariant reply = m_device->property(key.toUtf8()); -+ -+ if (reply.isValid()) { -+ m_cache.insert(key, reply); -+ } else { -+ qWarning() << "got invalid reply for cache:" << key; -+ } -+} -+ -+QString Device::introspect() const -+{ -+ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, m_udi, -+ DBUS_INTERFACE_INTROSPECT, "Introspect"); -+ QDBusPendingReply reply = QDBusConnection::systemBus().asyncCall(call); -+ reply.waitForFinished(); -+ -+ if (reply.isValid()) -+ return reply.value(); -+ else { -+ return QString(); -+ } -+} -+ -+QVariant Device::prop(const QString &key) const -+{ -+ checkCache(key); -+ return m_cache.value(key); -+} -+ -+bool Device::propertyExists(const QString &key) const -+{ -+ checkCache(key); -+ return m_cache.contains(key); -+} -+ -+QVariantMap Device::allProperties() const -+{ -+ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, m_udi, DBUS_INTERFACE_PROPS, "GetAll"); -+ -+ Q_FOREACH (const QString & iface, m_interfaces) { -+ if (iface.startsWith("org.freedesktop.DBus")) -+ continue; -+ call.setArguments(QVariantList() << iface); -+ QDBusPendingReply reply = QDBusConnection::systemBus().asyncCall(call); -+ reply.waitForFinished(); -+ -+ if (reply.isValid()) -+ m_cache.unite(reply.value()); -+ else -+ qWarning() << "Error getting props:" << reply.error().name() << reply.error().message(); -+ //qDebug() << "After iface" << iface << ", cache now contains" << m_cache.size() << "items"; -+ } -+ -+ return m_cache; -+} -+ -+bool Device::hasInterface(const QString &name) const -+{ -+ return m_interfaces.contains(name); -+} -+ -+QStringList Device::interfaces() const -+{ -+ return m_interfaces; -+} -+ -+void Device::initInterfaces() -+{ -+ m_interfaces.clear(); -+ const QString xmlData = introspect(); -+ QDomDocument dom; -+ dom.setContent(xmlData); -+ QDomNodeList ifaceNodeList = dom.elementsByTagName("interface"); -+ for (int i = 0; i < ifaceNodeList.count(); i++) { -+ QDomElement ifaceElem = ifaceNodeList.item(i).toElement(); -+ if (!ifaceElem.isNull()) -+ m_interfaces.append(ifaceElem.attribute("name")); -+ } -+ //qDebug() << "Device" << m_udi << "has interfaces:" << m_interfaces; -+} -+ -+void Device::slotPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps) -+{ -+ //Q_UNUSED(ifaceName); -+ -+ qDebug() << m_udi << "'s interface" << ifaceName << "changed props:"; -+ -+ QMap changeMap; -+ -+ Q_FOREACH(const QString & key, invalidatedProps) { -+ m_cache.remove(key); -+ changeMap.insert(key, Solid::GenericInterface::PropertyRemoved); -+ qDebug() << "\t invalidated:" << key; -+ } -+ -+ QMapIterator i(changedProps); -+ while (i.hasNext()) { -+ i.next(); -+ const QString key = i.key(); -+ m_cache.insert(key, i.value()); // replace the value -+ changeMap.insert(key, Solid::GenericInterface::PropertyModified); -+ qDebug() << "\t modified:" << key << ":" << m_cache.value(key); -+ } -+ -+ Q_EMIT propertyChanged(changeMap); -+ Q_EMIT changed(); -+} -+ -+void Device::slotInterfacesAdded(const QDBusObjectPath &object_path, const QVariantMapMap &interfaces_and_properties) -+{ -+ if (object_path.path() == m_udi) { -+ m_interfaces.append(interfaces_and_properties.keys()); -+ } -+} -+ -+void Device::slotInterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces) -+{ -+ if (object_path.path() == m_udi) { -+ Q_FOREACH(const QString & iface, interfaces) { -+ m_interfaces.removeAll(iface); -+ } -+ } -+} -+ -+ +QString Device::errorToString(const QString & error) const +{ + if (error == UD2_ERROR_UNAUTHORIZED || error == UD2_ERROR_NOT_AUTHORIZED) @@ -1384,10 +1310,10 @@ index 0000000..a3f780f +} diff --git a/solid/solid/backends/udisks2/udisksdevice.h b/solid/solid/backends/udisks2/udisksdevice.h new file mode 100644 -index 0000000..7e27634 +index 0000000..6038178 --- /dev/null +++ b/solid/solid/backends/udisks2/udisksdevice.h -@@ -0,0 +1,113 @@ +@@ -0,0 +1,104 @@ +/* + Copyright 2010 Michael Zanetti + Copyright 2010-2012 Lukáš Tinkl @@ -1429,6 +1355,8 @@ index 0000000..7e27634 +namespace UDisks2 +{ + ++class DeviceBackend; ++ +class Device: public Solid::Ifaces::Device +{ + Q_OBJECT @@ -1477,23 +1405,12 @@ index 0000000..7e27634 + void changed(); + void propertyChanged(const QMap &changes); + -+private Q_SLOTS: -+ void slotPropertiesChanged(const QString & ifaceName, const QVariantMap & changedProps, const QStringList & invalidatedProps); -+ void slotInterfacesAdded(const QDBusObjectPath &object_path, const QVariantMapMap &interfaces_and_properties); -+ void slotInterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); ++protected: ++ QPointer m_backend; + +private: + QString storageDescription() const; + QString volumeDescription() const; -+ mutable QDBusInterface *m_device; -+ QString m_udi; -+ mutable QVariantMap m_cache; -+ -+ void initInterfaces(); -+ QStringList m_interfaces; -+ -+ void checkCache(const QString &key) const; -+ QString introspect() const; +}; + +} @@ -1501,6 +1418,342 @@ index 0000000..7e27634 +} + +#endif // UDISKS2DEVICE_H +diff --git a/solid/solid/backends/udisks2/udisksdevicebackend.cpp b/solid/solid/backends/udisks2/udisksdevicebackend.cpp +new file mode 100644 +index 0000000..8131cb5 +--- /dev/null ++++ b/solid/solid/backends/udisks2/udisksdevicebackend.cpp +@@ -0,0 +1,239 @@ ++/* ++ Copyright 2010 Michael Zanetti ++ Copyright 2010-2012 Lukáš Tinkl ++ Copyright 2012 Dan Vrátil ++ ++ 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 . ++*/ ++ ++#include "udisksdevicebackend.h" ++ ++#include ++#include ++#include ++ ++#include "solid/deviceinterface.h" ++#include "solid/genericinterface.h" ++ ++using namespace Solid::Backends::UDisks2; ++ ++/* Static cache for DeviceBackends for all UDIs */ ++QMap DeviceBackend::s_backends; ++ ++DeviceBackend* DeviceBackend::backendForUDI(const QString& udi) ++{ ++ DeviceBackend *backend = 0; ++ if (udi.isEmpty()) { ++ return backend; ++ } ++ ++ if (s_backends.contains(udi)) { ++ backend = s_backends.value(udi); ++ } else { ++ backend = new DeviceBackend(udi); ++ s_backends.insert(udi, backend); ++ } ++ ++ return backend; ++} ++ ++void DeviceBackend::destroyBackend(const QString& udi) ++{ ++ if (s_backends.contains(udi)) { ++ DeviceBackend *backend = s_backends.value(udi); ++ s_backends.remove(udi); ++ delete backend; ++ } ++} ++ ++DeviceBackend::DeviceBackend(const QString& udi) ++ : m_udi(udi) ++{ ++ qDebug() << "Creating backend for device" << m_udi; ++ m_device = new QDBusInterface(UD2_DBUS_SERVICE, m_udi, ++ QString(), // no interface, we aggregate them ++ QDBusConnection::systemBus(), this); ++ ++ if (m_device->isValid()) { ++ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, m_udi, DBUS_INTERFACE_PROPS, "PropertiesChanged", this, ++ SLOT(slotPropertiesChanged(QString,QVariantMap,QStringList))); ++ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, UD2_DBUS_PATH, DBUS_INTERFACE_MANAGER, "InterfacesAdded", ++ this, SLOT(slotInterfacesAdded(QDBusObjectPath,QVariantMapMap))); ++ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, UD2_DBUS_PATH, DBUS_INTERFACE_MANAGER, "InterfacesRemoved", ++ this, SLOT(slotInterfacesRemoved(QDBusObjectPath,QStringList))); ++ ++ initInterfaces(); ++ } ++} ++ ++DeviceBackend::~DeviceBackend() ++{ ++ qDebug() << "Destroying backend for device" << m_udi; ++} ++ ++void DeviceBackend::initInterfaces() ++{ ++ m_interfaces.clear(); ++ ++ const QString xmlData = introspect(); ++ if (xmlData.isEmpty()) { ++ qDebug() << m_udi << "has no interfaces!"; ++ return; ++ } ++ ++ QDomDocument dom; ++ dom.setContent(xmlData); ++ ++ QDomNodeList ifaceNodeList = dom.elementsByTagName("interface"); ++ for (int i = 0; i < ifaceNodeList.count(); i++) { ++ QDomElement ifaceElem = ifaceNodeList.item(i).toElement(); ++ /* Accept only org.freedesktop.UDisks2.* interfaces so that when the device is unplugged, ++ * m_interfaces goes empty and we can easily verify that the device is gone. */ ++ if (!ifaceElem.isNull() && ifaceElem.attribute("name").startsWith(UD2_DBUS_SERVICE)) { ++ m_interfaces.append(ifaceElem.attribute("name")); ++ } ++ } ++ ++ qDebug() << m_udi << "has interfaces:" << m_interfaces; ++} ++ ++QStringList DeviceBackend::interfaces() const ++{ ++ return m_interfaces; ++} ++ ++const QString& DeviceBackend::udi() const ++{ ++ return m_udi; ++} ++ ++QVariant DeviceBackend::prop(const QString& key) const ++{ ++ checkCache(key); ++ return m_propertyCache.value(key); ++} ++ ++bool DeviceBackend::propertyExists(const QString& key) const ++{ ++ checkCache(key); ++ /* checkCache() will put an invalid QVariant in cache when the property ++ * does not exist, so check for validity, not for an actual presence. */ ++ return m_propertyCache.value(key).isValid(); ++} ++ ++QVariantMap DeviceBackend::allProperties() const ++{ ++ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, m_udi, DBUS_INTERFACE_PROPS, "GetAll"); ++ ++ Q_FOREACH (const QString & iface, m_interfaces) { ++ call.setArguments(QVariantList() << iface); ++ QDBusPendingReply reply = QDBusConnection::systemBus().call(call); ++ ++ if (reply.isValid()) { ++ m_propertyCache.unite(reply.value()); ++ } else { ++ qWarning() << "Error getting props:" << reply.error().name() << reply.error().message(); ++ } ++ //qDebug() << "After iface" << iface << ", cache now contains" << m_cache.size() << "items"; ++ } ++ ++ return m_propertyCache; ++} ++ ++QString DeviceBackend::introspect() const ++{ ++ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, m_udi, ++ DBUS_INTERFACE_INTROSPECT, "Introspect"); ++ QDBusPendingReply reply = QDBusConnection::systemBus().call(call); ++ ++ if (reply.isValid()) ++ return reply.value(); ++ else { ++ return QString(); ++ } ++} ++ ++void DeviceBackend::checkCache(const QString& key) const ++{ ++ if (m_propertyCache.isEmpty()) { // recreate the cache ++ allProperties(); ++ } ++ ++ if (m_propertyCache.contains(key)) { ++ return; ++ } ++ ++ QVariant reply = m_device->property(key.toUtf8()); ++ m_propertyCache.insert(key, reply); ++ ++ if (!reply.isValid()) { ++ /* Store the item in the cache anyway so next time we don't have to ++ * do the DBus call to find out it does not exist but just check whether ++ * prop(key).isValid() */ ++ qDebug() << m_udi << ": property" << key << "does not exist"; ++ } ++} ++ ++void DeviceBackend::slotPropertiesChanged(const QString& ifaceName, const QVariantMap& changedProps, const QStringList& invalidatedProps) ++{ ++ qDebug() << m_udi << "'s interface" << ifaceName << "changed props:"; ++ ++ QMap changeMap; ++ ++ Q_FOREACH(const QString & key, invalidatedProps) { ++ m_propertyCache.remove(key); ++ changeMap.insert(key, Solid::GenericInterface::PropertyRemoved); ++ qDebug() << "\t invalidated:" << key; ++ } ++ ++ QMapIterator i(changedProps); ++ while (i.hasNext()) { ++ i.next(); ++ const QString key = i.key(); ++ m_propertyCache.insert(key, i.value()); // replace the value ++ changeMap.insert(key, Solid::GenericInterface::PropertyModified); ++ qDebug() << "\t modified:" << key << ":" << m_propertyCache.value(key); ++ } ++ ++ Q_EMIT propertyChanged(changeMap); ++ Q_EMIT changed(); ++} ++ ++void DeviceBackend::slotInterfacesAdded(const QDBusObjectPath& object_path, const QVariantMapMap& interfaces_and_properties) ++{ ++ if (object_path.path() != m_udi) { ++ return; ++ } ++ ++ Q_FOREACH(const QString & iface, interfaces_and_properties.keys()) { ++ /* Don't store generic DBus interfaces */ ++ if (iface.startsWith(UD2_DBUS_SERVICE)) { ++ m_interfaces.append(interfaces_and_properties.keys()); ++ } ++ } ++} ++ ++void DeviceBackend::slotInterfacesRemoved(const QDBusObjectPath& object_path, const QStringList& interfaces) ++{ ++ if (object_path.path() != m_udi) { ++ return; ++ } ++ ++ Q_FOREACH(const QString & iface, interfaces) { ++ m_interfaces.removeAll(iface); ++ } ++} +diff --git a/solid/solid/backends/udisks2/udisksdevicebackend.h b/solid/solid/backends/udisks2/udisksdevicebackend.h +new file mode 100644 +index 0000000..829fa41 +--- /dev/null ++++ b/solid/solid/backends/udisks2/udisksdevicebackend.h +@@ -0,0 +1,84 @@ ++/* ++ Copyright 2010 Michael Zanetti ++ Copyright 2010-2012 Lukáš Tinkl ++ Copyright 2012 Dan Vrátil ++ ++ 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 . ++*/ ++ ++#ifndef UDISKSDEVICEBACKEND_H ++#define UDISKSDEVICEBACKEND_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "udisks2.h" ++ ++namespace Solid { ++namespace Backends { ++namespace UDisks2 { ++ ++class DeviceBackend: public QObject { ++ ++ Q_OBJECT ++ ++ public: ++ static DeviceBackend* backendForUDI(const QString &udi); ++ static void destroyBackend(const QString &udi); ++ ++ DeviceBackend(const QString &udi); ++ ~DeviceBackend(); ++ ++ QVariant prop(const QString &key) const; ++ bool propertyExists(const QString &key) const; ++ QVariantMap allProperties() const; ++ ++ QStringList interfaces() const; ++ const QString & udi() const; ++ ++ Q_SIGNALS: ++ void propertyChanged(const QMap &changeMap); ++ void changed(); ++ ++ private Q_SLOTS: ++ void slotInterfacesAdded(const QDBusObjectPath &object_path, const QVariantMapMap &interfaces_and_properties); ++ void slotInterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces); ++ void slotPropertiesChanged(const QString &ifaceName, const QVariantMap &changedProps, const QStringList &invalidatedProps); ++ ++ private: ++ void initInterfaces(); ++ QString introspect() const; ++ void checkCache(const QString &key) const; ++ ++ QDBusInterface *m_device; ++ ++ mutable QVariantMap m_propertyCache; ++ QStringList m_interfaces; ++ QString m_udi; ++ ++ static QMap s_backends; ++ ++}; ++ ++} /* namespace UDisks2 */ ++} /* namespace Backends */ ++} /* namespace Solid */ ++ ++#endif /* UDISKSDEVICEBACKEND_H */ +\ No newline at end of file diff --git a/solid/solid/backends/udisks2/udisksdeviceinterface.cpp b/solid/solid/backends/udisks2/udisksdeviceinterface.cpp new file mode 100644 index 0000000..9fa60e5 @@ -1818,10 +2071,10 @@ index 0000000..d225f32 +#endif // SOLID_BACKENDS_UDISKS2_GENERICINTERFACE_H diff --git a/solid/solid/backends/udisks2/udisksmanager.cpp b/solid/solid/backends/udisks2/udisksmanager.cpp new file mode 100644 -index 0000000..fab5208 +index 0000000..35b0d23 --- /dev/null +++ b/solid/solid/backends/udisks2/udisksmanager.cpp -@@ -0,0 +1,269 @@ +@@ -0,0 +1,248 @@ +/* + Copyright 2012 Lukáš Tinkl + @@ -1843,6 +2096,7 @@ index 0000000..fab5208 +*/ + +#include "udisksmanager.h" ++#include "udisksdevicebackend.h" + +#include +#include @@ -1900,6 +2154,10 @@ index 0000000..fab5208 + +Manager::~Manager() +{ ++ while (!m_deviceCache.isEmpty()) { ++ QString udi = m_deviceCache.takeFirst(); ++ DeviceBackend::destroyBackend(udi); ++ } +} + +QObject* Manager::createDevice(const QString& udi) @@ -1951,38 +2209,11 @@ index 0000000..fab5208 + +QStringList Manager::allDevices() +{ -+ m_deviceCache.clear(); -+ -+#if 0 -+ QDBusPendingReply reply = m_manager.GetManagedObjects(); -+ reply.waitForFinished(); -+ if (!reply.isError()) { // enum devices -+ m_deviceCache << udiPrefix(); -+ -+ Q_FOREACH(const QDBusObjectPath &path, reply.value().keys()) { -+ const QString udi = path.path(); -+ //qDebug() << "Adding device" << udi; -+ -+ if (udi == UD2_DBUS_PATH_MANAGER || udi == UD2_UDI_DISKS_PREFIX || udi.startsWith(UD2_DBUS_PATH_JOBS)) -+ continue; -+ -+ Device device(udi); -+ if (device.mightBeOpticalDisc()) { -+ QDBusConnection::systemBus().connect(UD2_DBUS_SERVICE, udi, DBUS_INTERFACE_PROPS, "PropertiesChanged", this, -+ SLOT(slotMediaChanged(QDBusMessage))); -+ if (!device.isOpticalDisc()) // skip empty CD disc -+ continue; -+ } -+ -+ m_deviceCache.append(udi); -+ } ++ /* Clear the cache, destroy all backends */ ++ while (!m_deviceCache.isEmpty()) { ++ QString udi= m_deviceCache.takeFirst(); ++ DeviceBackend::destroyBackend(udi); + } -+ else // show error -+ { -+ qWarning() << "Failed enumerating UDisks2 objects:" << reply.error().name() << "\n" << reply.error().message(); -+ } -+ -+#endif + + introspect("/org/freedesktop/UDisks2/block_devices", true /*checkOptical*/); + introspect("/org/freedesktop/UDisks2/drives"); @@ -1994,8 +2225,7 @@ index 0000000..fab5208 +{ + QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, path, + DBUS_INTERFACE_INTROSPECT, "Introspect"); -+ QDBusPendingReply reply = QDBusConnection::systemBus().asyncCall(call); -+ reply.waitForFinished(); ++ QDBusPendingReply reply = QDBusConnection::systemBus().call(call); + + if (reply.isValid()) { + QDomDocument dom; @@ -2058,6 +2288,7 @@ index 0000000..fab5208 + if (!udi.isEmpty() && (interfaces.isEmpty() || device.interfaces().isEmpty() || device.interfaces().contains(UD2_DBUS_INTERFACE_FILESYSTEM))) { + Q_EMIT deviceRemoved(udi); + m_deviceCache.removeAll(udi); ++ DeviceBackend::destroyBackend(udi); + } +} + @@ -2080,6 +2311,7 @@ index 0000000..fab5208 + if (m_deviceCache.contains(udi) && size == 0) { // we know the optdisc, got removed + Q_EMIT deviceRemoved(udi); + m_deviceCache.removeAll(udi); ++ DeviceBackend::destroyBackend(udi); + } +} + @@ -2547,10 +2779,10 @@ index 0000000..0cdcc66 +#endif // UDISKS2OPTICALDISC_H diff --git a/solid/solid/backends/udisks2/udisksopticaldrive.cpp b/solid/solid/backends/udisks2/udisksopticaldrive.cpp new file mode 100644 -index 0000000..f4351a7 +index 0000000..4df18b1 --- /dev/null +++ b/solid/solid/backends/udisks2/udisksopticaldrive.cpp -@@ -0,0 +1,222 @@ +@@ -0,0 +1,226 @@ +/* + Copyright 2010 Michael Zanetti + Copyright 2010-2012 Lukáš Tinkl @@ -2591,7 +2823,11 @@ index 0000000..f4351a7 +using namespace Solid::Backends::UDisks2; + +OpticalDrive::OpticalDrive(Device *device) -+ : StorageDrive(device), m_ejectInProgress(false), m_readSpeed(0), m_writeSpeed(0), m_speedsInit(false) ++ : StorageDrive(device) ++ , m_ejectInProgress(false) ++ , m_readSpeed(0) ++ , m_writeSpeed(0) ++ , m_speedsInit(false) +{ + m_device->registerAction("eject", this, + SLOT(slotEjectRequested()), @@ -2612,7 +2848,7 @@ index 0000000..f4351a7 + m_device->broadcastActionRequested("eject"); + + const QString path = m_device->udi(); -+ QDBusConnection c = QDBusConnection::systemBus(); ++ QDBusConnection c = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "Solid::Udisks2::OpticalDrive::" + path); + + // if the device is mounted, unmount first + QString blockPath; @@ -2862,10 +3098,10 @@ index 0000000..4c98ef5 +#endif // UDISKS2OPTICALDRIVE_H diff --git a/solid/solid/backends/udisks2/udisksstorageaccess.cpp b/solid/solid/backends/udisks2/udisksstorageaccess.cpp new file mode 100644 -index 0000000..f28540b +index 0000000..6958459 --- /dev/null +++ b/solid/solid/backends/udisks2/udisksstorageaccess.cpp -@@ -0,0 +1,362 @@ +@@ -0,0 +1,390 @@ +/* + Copyright 2009 Pino Toscano + Copyright 2009-2012 Lukáš Tinkl @@ -2890,10 +3126,10 @@ index 0000000..f28540b +#include "udisksstorageaccess.h" +#include "udisks2.h" + -+#include +#include +#include +#include ++#include + +using namespace Solid::Backends::UDisks2; + @@ -2931,9 +3167,11 @@ index 0000000..f28540b +bool StorageAccess::isAccessible() const +{ + if (isLuksDevice()) { // check if the cleartext slave is mounted -+ if (m_clearTextPath.isEmpty() || m_clearTextPath == "/") ++ const QString path = clearTextPath(); ++ //qDebug() << Q_FUNC_INFO << "CLEARTEXT device path: " << path; ++ if (path.isEmpty() || path == "/") + return false; -+ Device holderDevice(m_clearTextPath); ++ Device holderDevice(path); + return holderDevice.isMounted(); + } + @@ -2942,15 +3180,13 @@ index 0000000..f28540b + +QString StorageAccess::filePath() const +{ -+ if (!isAccessible()) -+ return QString(); -+ + QByteArrayList mntPoints; + + if (isLuksDevice()) { // encrypted (and unlocked) device -+ if (m_clearTextPath.isEmpty() || m_clearTextPath == "/") ++ const QString path = clearTextPath(); ++ if (path.isEmpty() || path == "/") + return QString(); -+ Device holderDevice(m_clearTextPath); ++ Device holderDevice(path); + mntPoints = qdbus_cast(holderDevice.prop("MountPoints")); + if (!mntPoints.isEmpty()) + return QFile::decodeName(mntPoints.first()); // FIXME Solid doesn't support multiple mount points @@ -2968,7 +3204,7 @@ index 0000000..f28540b + +bool StorageAccess::isIgnored() const +{ -+ return m_device->prop("HintIgnore").toBool(); // FIXME tune ++ return m_device->prop("HintIgnore").toBool(); +} + +bool StorageAccess::setup() @@ -2978,7 +3214,7 @@ index 0000000..f28540b + m_setupInProgress = true; + m_device->broadcastActionRequested("setup"); + -+ if (m_device->isEncryptedContainer()) ++ if (m_device->isEncryptedContainer() && clearTextPath().isEmpty()) + return requestPassphrase(); + else + return mount(); @@ -3005,17 +3241,16 @@ index 0000000..f28540b + updateCache(); + + if (old_isAccessible != m_isAccessible) { -+ Q_EMIT accessibilityChanged(m_isAccessible, isLuksDevice() ? m_clearTextPath : m_device->udi()); ++ Q_EMIT accessibilityChanged(m_isAccessible, m_device->udi()); + } +} + -+void StorageAccess::slotDBusReply( const QDBusMessage & reply ) ++void StorageAccess::slotDBusReply( const QDBusMessage & /*reply*/ ) +{ ++ const QString ctPath = clearTextPath(); + if (m_setupInProgress) + { + if (isLuksDevice() && !isAccessible()) { // unlocked device, now mount it -+ if (reply.type() == QDBusMessage::ReplyMessage) // we've got a response from Unlock -+ m_clearTextPath = reply.arguments().value(0).value().path(); + mount(); + } + else // Don't broadcast setupDone unless the setup is really done. (Fix kde#271156) @@ -3028,17 +3263,17 @@ index 0000000..f28540b + } + else if (m_teardownInProgress) // FIXME + { -+ if (isLuksDevice() && !m_clearTextPath.isEmpty() && m_clearTextPath != "/") // unlocked device, lock it ++ if (isLuksDevice() && !ctPath.isEmpty() && ctPath != "/") // unlocked device, lock it + { + callCryptoTeardown(); + } -+ else if (!m_clearTextPath.isEmpty() && m_clearTextPath != "/") { ++ else if (!ctPath.isEmpty() && ctPath != "/") { + callCryptoTeardown(true); // Lock crypted parent + } + else + { + // try to "eject" (aka safely remove) from the (parent) drive, e.g. SD card from a reader -+ QString drivePath = m_device->prop("Drive").value().path(); ++ QString drivePath = m_device->drivePath(); + if (!drivePath.isEmpty() || drivePath != "/") + { + Device drive(drivePath); @@ -3063,6 +3298,8 @@ index 0000000..f28540b + +void StorageAccess::slotDBusError( const QDBusError & error ) +{ ++ //qDebug() << Q_FUNC_INFO << "DBUS ERROR:" << error.name() << error.message(); ++ + if (m_setupInProgress) + { + m_setupInProgress = false; @@ -3074,7 +3311,6 @@ index 0000000..f28540b + else if (m_teardownInProgress) + { + m_teardownInProgress = false; -+ m_clearTextPath.clear(); + m_device->broadcastActionDone("teardown", m_device->errorToSolidError(error.name()), + m_device->errorToString(error.name()) + ": " + error.message()); + checkAccessibility(); @@ -3106,7 +3342,6 @@ index 0000000..f28540b +void StorageAccess::slotTeardownDone(int error, const QString &errorString) +{ + m_teardownInProgress = false; -+ m_clearTextPath.clear(); + Q_EMIT teardownDone(static_cast(error), errorString, m_device->udi()); + + checkAccessibility(); @@ -3115,9 +3350,10 @@ index 0000000..f28540b +bool StorageAccess::mount() +{ + QString path = m_device->udi(); ++ const QString ctPath = clearTextPath(); + -+ if (isLuksDevice()) { // mount options for the cleartext volume -+ path = m_clearTextPath; ++ if (isLuksDevice() && !ctPath.isEmpty()) { // mount options for the cleartext volume ++ path = ctPath; + } + + QDBusConnection c = QDBusConnection::systemBus(); @@ -3137,9 +3373,10 @@ index 0000000..f28540b +bool StorageAccess::unmount() +{ + QString path = m_device->udi(); ++ const QString ctPath = clearTextPath(); + -+ if (isLuksDevice()) { // unmount options for the cleartext volume -+ path = m_clearTextPath; ++ if (isLuksDevice() && !ctPath.isEmpty()) { // unmount options for the cleartext volume ++ path = ctPath; + } + + QDBusConnection c = QDBusConnection::systemBus(); @@ -3160,6 +3397,35 @@ index 0000000..f28540b + return "/org/kde/solid/UDisks2StorageAccess_"+QString::number(number++); +} + ++QString StorageAccess::clearTextPath() const ++{ ++ const QString prefix = "/org/freedesktop/UDisks2/block_devices"; ++ QDBusMessage call = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, prefix, ++ DBUS_INTERFACE_INTROSPECT, "Introspect"); ++ QDBusPendingReply reply = QDBusConnection::systemBus().asyncCall(call); ++ reply.waitForFinished(); ++ ++ if (reply.isValid()) { ++ QDomDocument dom; ++ dom.setContent(reply.value()); ++ QDomNodeList nodeList = dom.documentElement().elementsByTagName("node"); ++ for (int i = 0; i < nodeList.count(); i++) { ++ QDomElement nodeElem = nodeList.item(i).toElement(); ++ if (!nodeElem.isNull() && nodeElem.hasAttribute("name")) { ++ const QString udi = prefix + "/" + nodeElem.attribute("name"); ++ Device holderDevice(udi); ++ ++ if (m_device->udi() == holderDevice.prop("CryptoBackingDevice").value().path()) { ++ //qDebug() << Q_FUNC_INFO << "CLEARTEXT device path: " << udi; ++ return udi; ++ } ++ } ++ } ++ } ++ ++ return QString(); ++} ++ +bool StorageAccess::requestPassphrase() +{ + QString udi = m_device->udi(); @@ -3222,15 +3488,13 @@ index 0000000..f28540b + UD2_DBUS_INTERFACE_ENCRYPTED, "Lock"); + msg << QVariantMap(); // options, unused now + -+ m_clearTextPath.clear(); -+ + return c.callWithCallback(msg, this, + SLOT(slotDBusReply(const QDBusMessage &)), + SLOT(slotDBusError(const QDBusError &))); +} diff --git a/solid/solid/backends/udisks2/udisksstorageaccess.h b/solid/solid/backends/udisks2/udisksstorageaccess.h new file mode 100644 -index 0000000..2901067 +index 0000000..ec91f89 --- /dev/null +++ b/solid/solid/backends/udisks2/udisksstorageaccess.h @@ -0,0 +1,104 @@ @@ -3322,6 +3586,7 @@ index 0000000..2901067 + bool callCryptoTeardown( bool actOnParent=false ); + + QString generateReturnObjectPath(); ++ QString clearTextPath() const; + +private: + bool m_isAccessible; @@ -3329,7 +3594,6 @@ index 0000000..2901067 + bool m_teardownInProgress; + bool m_passphraseRequested; + QString m_lastReturnObject; -+ QString m_clearTextPath; // path to the unlocked cleartext device + + static const int s_unmountTimeout = 0x7fffffff; +}; @@ -3733,20 +3997,23 @@ index 0000000..2ca04d2 + +#endif // UDISKS2STORAGEVOLUME_H diff --git a/solid/solid/managerbase.cpp b/solid/solid/managerbase.cpp -index fb5a67c..d58736e 100644 +index fb5a67c..4084323 100644 --- a/solid/solid/managerbase.cpp +++ b/solid/solid/managerbase.cpp -@@ -30,8 +30,7 @@ +@@ -30,8 +30,11 @@ #if defined (Q_OS_MAC) #include "backends/iokit/iokitmanager.h" #elif defined (Q_OS_UNIX) -#include "backends/hal/halmanager.h" --#include "backends/udisks/udisksmanager.h" ++#if defined (WITH_SOLID_UDISKS2) +#include "backends/udisks2/udisksmanager.h" ++#else + #include "backends/udisks/udisksmanager.h" ++#endif #include "backends/upower/upowermanager.h" #if defined (HUPNP_FOUND) -@@ -71,22 +70,13 @@ void Solid::ManagerBasePrivate::loadBackends() +@@ -71,22 +74,17 @@ void Solid::ManagerBasePrivate::loadBackends() # elif defined(Q_WS_WIN) && defined(HAVE_WBEM) && !defined(_WIN32_WCE) m_backends << new Solid::Backends::Wmi::WmiManager(0); @@ -3762,8 +4029,11 @@ index fb5a67c..d58736e 100644 # if defined(UDEV_FOUND) m_backends << new Solid::Backends::UDev::UDevManager(0); # endif -- m_backends << new Solid::Backends::UDisks::UDisksManager(0) ++# if defined(WITH_SOLID_UDISKS2) + m_backends << new Solid::Backends::UDisks2::Manager(0) ++# else + m_backends << new Solid::Backends::UDisks::UDisksManager(0) ++# endif << new Solid::Backends::UPower::UPowerManager(0) << new Solid::Backends::Fstab::FstabManager(0); - } diff --git a/kdelibs-udisks2-kfileplacesdevicecache.patch b/kdelibs-udisks2-kfileplacesdevicecache.patch new file mode 100644 index 0000000..5e45d6f --- /dev/null +++ b/kdelibs-udisks2-kfileplacesdevicecache.patch @@ -0,0 +1,406 @@ +diff --git a/kfile/CMakeLists.txt b/kfile/CMakeLists.txt +index ceae140..c7c4d3d 100644 +--- a/kfile/CMakeLists.txt ++++ b/kfile/CMakeLists.txt +@@ -20,6 +20,7 @@ set(kfile_LIB_SRCS + kfilefiltercombo.cpp + kfiletreeview.cpp + kfilewidget.cpp ++ kfileplacesdevicecache.cpp + kfileplacesitem.cpp + kfileplacesmodel.cpp + kfileplacessharedbookmarks.cpp +@@ -63,6 +64,7 @@ install( FILES + kdirselectdialog.h + kdirsortfilterproxymodel.h + kfilefiltercombo.h ++ kfileplacesdevicecache.h + kfileplacesmodel.h + kfileplacesview.h + kfilepreviewgenerator.h +diff --git a/kfile/kfileplacesdevicecache.cpp b/kfile/kfileplacesdevicecache.cpp +new file mode 100644 +index 0000000..40f7242 +--- /dev/null ++++ b/kfile/kfileplacesdevicecache.cpp +@@ -0,0 +1,174 @@ ++/* ++ Copyright (C) 2012 Dan Vrátil ++ ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Library General Public ++ License version 2 as published by the Free Software Foundation. ++ ++ 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 ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public License ++ along with this library; see the file COPYING.LIB. If not, write to ++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ Boston, MA 02110-1301, USA. ++*/ ++ ++#include "kfileplacesdevicecache.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++KFilePlacesDeviceCache* KFilePlacesDeviceCache::s_instance = 0; ++ ++class KFilePlacesDeviceCache::Private ++{ ++ public: ++ Private(KFilePlacesDeviceCache *parent): ++ queryRunning(false), ++ q(parent) ++ { } ++ ++ ~Private() ++ { } ++ ++ /* This method runs asynchronously in thread */ ++ QSet listSolidDevicesAsync() ++ { ++ QSet udis; ++ ++ kDebug() << "Querying Solid devices..."; ++ const QList& deviceList = Solid::Device::listFromQuery(solidPredicate); ++ kDebug() << "Retrieved" << deviceList.count() << "devices"; ++ ++ Q_FOREACH (const Solid::Device& device, deviceList) { ++ if (solidPredicate.matches(device)) { ++ udis << device.udi(); ++ } ++ } ++ ++ return udis; ++ } ++ ++ void _k_slotDeviceAdded(const QString &udi) ++ { ++ devicesCache << udi; ++ ++ Q_EMIT q->deviceAdded(udi); ++ } ++ ++ void _k_slotDeviceRemoved(const QString &udi) ++ { ++ if (!devicesCache.contains(udi)) { ++ return; ++ } ++ ++ devicesCache.remove(udi); ++ ++ Q_EMIT q->deviceRemoved(udi); ++ } ++ ++ void _k_listSolidDevicesFinished() ++ { ++ Q_FOREACH (const QString& device, futureWatcher->result()) { ++ _k_slotDeviceAdded(device); ++ } ++ ++ delete futureWatcher; ++ futureWatcher = 0; ++ ++ queryRunning = false; ++ } ++ ++ Solid::Predicate solidPredicate; ++ ++ QFutureWatcher< QSet >* futureWatcher; ++ ++ /* Static */ ++ QSet devicesCache; ++ bool queryRunning; ++ ++ KFilePlacesDeviceCache *q; ++}; ++ ++KFilePlacesDeviceCache::KFilePlacesDeviceCache(): ++ QObject(), ++ d(new Private(this)) ++{ ++ Solid::DeviceNotifier* notifier = Solid::DeviceNotifier::instance(); ++ connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(_k_slotDeviceAdded(QString))); ++ connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(_k_slotDeviceRemoved(QString))); ++ ++ QString predicate("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" ++ " OR " ++ "[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]" ++ " OR " ++ "OpticalDisc.availableContent & 'Audio' ]" ++ " OR " ++ "StorageAccess.ignored == false ]"); ++ ++ if (KProtocolInfo::isKnownProtocol("mtp")) { ++ predicate.prepend("["); ++ predicate.append(" OR PortableMediaPlayer.supportedProtocols == 'mtp']"); ++ } ++ ++ d->solidPredicate = Solid::Predicate::fromString(predicate); ++} ++ ++KFilePlacesDeviceCache* KFilePlacesDeviceCache::self() ++{ ++ static QMutex mutex; ++ ++ mutex.lock(); ++ if (s_instance == 0) { ++ s_instance = new KFilePlacesDeviceCache(); ++ } ++ mutex.unlock(); ++ ++ return s_instance; ++} ++ ++KFilePlacesDeviceCache::~KFilePlacesDeviceCache() ++{ ++ Solid::DeviceNotifier* notifier = Solid::DeviceNotifier::instance(); ++ disconnect(notifier, SIGNAL(deviceAdded(QString))); ++ disconnect(notifier, SIGNAL(deviceRemoved(QString))); ++ ++ delete d; ++} ++ ++const Solid::Predicate& KFilePlacesDeviceCache::predicate() const ++{ ++ return d->solidPredicate; ++} ++ ++const QSet& KFilePlacesDeviceCache::devices() const ++{ ++ kDebug(); ++ if (d->devicesCache.isEmpty() && !d->queryRunning) { ++ d->queryRunning = true; ++ d->futureWatcher = new QFutureWatcher< QSet >; ++ connect(d->futureWatcher, SIGNAL(finished()), this, SLOT(_k_listSolidDevicesFinished())); ++ ++ QFuture< QSet > future = QtConcurrent::run(d, &Private::listSolidDevicesAsync); ++ d->futureWatcher->setFuture(future); ++ } ++ ++ return d->devicesCache; ++} ++ ++ ++ ++#include "kfileplacesdevicecache.moc" +diff --git a/kfile/kfileplacesdevicecache.h b/kfile/kfileplacesdevicecache.h +new file mode 100644 +index 0000000..7293d03 +--- /dev/null ++++ b/kfile/kfileplacesdevicecache.h +@@ -0,0 +1,96 @@ ++/* ++ Copyright (C) 2012 Dan Vrátil ++ ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Library General Public ++ License version 2 as published by the Free Software Foundation. ++ ++ 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 ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public License ++ along with this library; see the file COPYING.LIB. If not, write to ++ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ Boston, MA 02110-1301, USA. ++*/ ++ ++#ifndef KFILEPLACESDEVICECACHE_H ++#define KFILEPLACESDEVICECACHE_H ++ ++#include ++ ++#include ++#include ++ ++#include ++ ++/** ++ * @short Asynchronous cache for Solid devices ++ * ++ * Purpose of this cache is to load Solid devices asynchronously, because ++ * udisks2 backend can take quite a lot of time to enumerate devices, and ++ * since Solid does not have async API, the UI thread is blocked for too long. ++ * ++ * When libsolid2 with asynchronous API is available, this class can go away. ++ * ++ * The cache keeps itself up-to-date and notifies listeners when a ++ * new devices is added or removed. ++ */ ++class KFILE_EXPORT KFilePlacesDeviceCache : public QObject ++{ ++ Q_OBJECT ++ ++public: ++ /** ++ * Returns a global instance of the cache ++ */ ++ static KFilePlacesDeviceCache* self(); ++ ++ /** ++ * Returns list of Solid devices. ++ * ++ * This method always returns immediatelly. When there are no ++ * devices in the cache, it returns an empty list and will asynchronously ++ * query Solid for devices and will notify listeners by emitting ++ * deviceAdded() signal for each devices loaded. ++ */ ++ const QSet& devices() const; ++ ++ /** ++ * Returns Solid::Predicate used to obtain devices from Solid ++ */ ++ const Solid::Predicate& predicate() const; ++ ++Q_SIGNALS: ++ /** ++ * Emitted whenever a new device is discovered. ++ * ++ * @param udi UDI (Universal Device ID) of the newly discovered device ++ */ ++ void deviceAdded(const QString& udi); ++ ++ /** ++ * Emitted whenever a device is removed from system ++ * ++ * @param udi UDI (Universal Device ID) of the removed device ++ */ ++ void deviceRemoved(const QString& udi); ++ ++private: ++ Q_PRIVATE_SLOT(d, void _k_listSolidDevicesFinished()) ++ Q_PRIVATE_SLOT(d, void _k_slotDeviceAdded(const QString&)) ++ Q_PRIVATE_SLOT(d, void _k_slotDeviceRemoved(const QString&)) ++ ++ class Private; ++ Private * const d; ++ friend class Private; ++ ++ explicit KFilePlacesDeviceCache(); ++ virtual ~KFilePlacesDeviceCache(); ++ ++ static KFilePlacesDeviceCache* s_instance; ++}; ++ ++#endif // KFILEPLACESDEVICECACHE_H +diff --git a/kfile/kfileplacesmodel.cpp b/kfile/kfileplacesmodel.cpp +index 0192926..e0b01c6 100644 +--- a/kfile/kfileplacesmodel.cpp ++++ b/kfile/kfileplacesmodel.cpp +@@ -20,6 +20,7 @@ + #include "kfileplacesmodel.h" + #include "kfileplacesitem_p.h" + #include "kfileplacessharedbookmarks_p.h" ++#include "kfileplacesdevicecache.h" + + #ifdef _WIN32_WCE + #include "Windows.h" +@@ -49,14 +50,12 @@ + #include + #include + +-#include + #include + #include + #include + #include + #include + #include +-#include + + class KFilePlacesModel::Private + { +@@ -74,7 +73,6 @@ public: + QSet availableDevices; + QMap setupInProgress; + +- Solid::Predicate predicate; + KBookmarkManager *bookmarkManager; + KFilePlacesSharedBookmarks * sharedBookmarks; + +@@ -149,30 +147,12 @@ KFilePlacesModel::KFilePlacesModel(QObject *parent) + // create after, so if we have own places, they are added afterwards, in case of equal priorities + d->sharedBookmarks = new KFilePlacesSharedBookmarks(d->bookmarkManager); + +- QString predicate("[[[[ StorageVolume.ignored == false AND [ StorageVolume.usage == 'FileSystem' OR StorageVolume.usage == 'Encrypted' ]]" +- " OR " +- "[ IS StorageAccess AND StorageDrive.driveType == 'Floppy' ]]" +- " OR " +- "OpticalDisc.availableContent & 'Audio' ]" +- " OR " +- "StorageAccess.ignored == false ]"); +- +- if (KProtocolInfo::isKnownProtocol("mtp")) { +- predicate.prepend("["); +- predicate.append(" OR PortableMediaPlayer.supportedProtocols == 'mtp']"); +- } +- +- d->predicate = Solid::Predicate::fromString(predicate); +- +- Q_ASSERT(d->predicate.isValid()); +- + connect(d->bookmarkManager, SIGNAL(changed(QString,QString)), + this, SLOT(_k_reloadBookmarks())); + connect(d->bookmarkManager, SIGNAL(bookmarksChanged(QString)), + this, SLOT(_k_reloadBookmarks())); + +- d->_k_reloadBookmarks(); +- QTimer::singleShot(0, this, SLOT(_k_initDeviceList())); ++ d->_k_initDeviceList(); + } + + KFilePlacesModel::~KFilePlacesModel() +@@ -313,30 +293,21 @@ QModelIndex KFilePlacesModel::closestItem(const KUrl &url) const + + void KFilePlacesModel::Private::_k_initDeviceList() + { +- Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance(); +- +- connect(notifier, SIGNAL(deviceAdded(QString)), ++ KFilePlacesDeviceCache *cache = KFilePlacesDeviceCache::self(); ++ connect(cache, SIGNAL(deviceAdded(QString)), + q, SLOT(_k_deviceAdded(QString))); +- connect(notifier, SIGNAL(deviceRemoved(QString)), ++ connect(cache, SIGNAL(deviceRemoved(QString)), + q, SLOT(_k_deviceRemoved(QString))); + +- const QList &deviceList = Solid::Device::listFromQuery(predicate); +- +- foreach(const Solid::Device &device, deviceList) { +- availableDevices << device.udi(); +- } ++ availableDevices = cache->devices(); + + _k_reloadBookmarks(); + } + + void KFilePlacesModel::Private::_k_deviceAdded(const QString &udi) + { +- Solid::Device d(udi); +- +- if (predicate.matches(d)) { +- availableDevices << udi; +- _k_reloadBookmarks(); +- } ++ availableDevices << udi; ++ _k_reloadBookmarks(); + } + + void KFilePlacesModel::Private::_k_deviceRemoved(const QString &udi) diff --git a/kdelibs.spec b/kdelibs.spec index f33148c..59c736c 100644 --- a/kdelibs.spec +++ b/kdelibs.spec @@ -24,7 +24,7 @@ %global dbusmenu_qt_version %(pkg-config --modversion dbusmenu-qt 2>/dev/null || echo %{dbusmenu_qt_ver}) Summary: KDE Libraries -Version: 4.9.3 +Version: 4.9.4 Release: 4%{?dist} Name: kdelibs @@ -124,6 +124,11 @@ Patch45: kdelibs-4.7.3-halectomy.patch # udisks2 Solid backend Patch47: kdelibs-udisks2-backend.patch +# cache to improve performance of apps using Solid with udisks2 (#868530) +# disable now, this patch causes new regression, backend devices are destroyed! +# the latest solid backend works fine without this patch +# Patch48: kdelibs-udisks2-kfileplacesdevicecache.patch + ## upstreamable # knewstuff2 variant of: # https://git.reviewboard.kde.org/r/102439/ @@ -155,8 +160,12 @@ Patch56: kdelibs-4.9.1-FindKipi-libkipi2.patch # required or not -- rex Patch58: kdelibs-cmake_python3.patch +# make filter working +Patch59: kdelibs-4.9.3-kcm_ssl.patch + ## upstream -Patch100: kdelibs-4.9.3-delete-downloadDialog.patch +Patch100: 0001-Revert-Also-check-parent-mimetypes-in-protocolForArc.patch +Patch101: 0001-Fix-crash-when-no-service-was-selected-user-clicked-.patch ## security fix # Not Upstreamed? why not ? -- Rex @@ -164,6 +173,7 @@ Patch200: kdelibs-4.3.1-CVE-2009-2702.patch # rhel patches Patch300: kdelibs-4.8.3-webkit.patch +Patch301: kdelibs-4.9.3-dot.patch # kmailservice moved here Conflicts: kdelibs3 < 3.5.10-38 @@ -314,6 +324,7 @@ sed -i -e "s|@@VERSION_RELEASE@@|%{version}-%{release}|" kio/kio/kprotocolmanage %if "%{?udisks}" == "udisks2" %patch47 -p1 -b .udisks2backend +#patch48 -p1 -b .kfileplacesdevicescache %else %patch45 -p1 -b .halectomy %endif @@ -327,9 +338,11 @@ sed -i -e "s|@@VERSION_RELEASE@@|%{version}-%{release}|" kio/kio/kprotocolmanage %patch55 -p1 -b .FindSamba-samba4 %patch56 -p1 -b .FindKipi-libkipi2 %patch58 -p1 -b .cmake_python3 +%patch59 -p1 -b .filter # upstream patches -%patch100 -p1 -b .delete-downloadDialog +%patch100 -p1 -b .kio +%patch101 -p1 -b .crash # security fixes %patch200 -p1 -b .CVE-2009-2702 @@ -337,6 +350,7 @@ sed -i -e "s|@@VERSION_RELEASE@@|%{version}-%{release}|" kio/kio/kprotocolmanage # rhel patches %if 0%{?rhel} %patch300 -p1 -b .webkit +%patch301 -p1 -b .dot %endif %build @@ -588,6 +602,30 @@ rm -rf %{buildroot} %changelog +* Thu Dec 06 2012 Than Ngo - 6:4.9.4-4 +- apply upstream patch to fix crash when no service was selected + +* Thu Dec 06 2012 Than Ngo - 6:4.9.4-3 +- apply upstream patch to revert the check parent mimetypes in + protocolForArchiveMimetype() (kde#311214) + +* Tue Dec 04 2012 Than Ngo - 6:4.9.4-2 +- disable kfileplacesdevicecache which causes bad regression +- add rhel condition + +* Mon Dec 03 2012 Than Ngo - 6:4.9.4-1 +- 4.9.4 +- update udisks2 backend patch to fix ghost devices + +* Fri Nov 30 2012 Dan Vrátil - 6:4.9.3-7 +- update udisks2 backend patch + +* Thu Nov 29 2012 Than Ngo - 6:4.9.3-6 +- fix file filter + +* Thu Nov 29 2012 Lukáš Tinkl 6:4.9.3-5 +- update udisks2 backend patch + * Fri Nov 23 2012 Jan Grulich 6:4.9.3-4 - Fix previous patch diff --git a/sources b/sources index de58ca9..cc25efd 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -91e9cf8446491e7e852b04be7a22c61c kdelibs-4.9.3.tar.xz +ec4b28e42cdcb26ddba1c1075e02a166 kdelibs-4.9.4.tar.xz