diff options
Diffstat (limited to 'src/extensions')
14 files changed, 467 insertions, 101 deletions
diff --git a/src/extensions/applicationextension/mapplicationextensionarea.cpp b/src/extensions/applicationextension/mapplicationextensionarea.cpp index f06a9545..63215ea9 100644 --- a/src/extensions/applicationextension/mapplicationextensionarea.cpp +++ b/src/extensions/applicationextension/mapplicationextensionarea.cpp @@ -42,8 +42,8 @@ void MApplicationExtensionAreaPrivate::init(const QString &interface) { Q_Q(MApplicationExtensionArea); extensionManager = QSharedPointer<MApplicationExtensionManager>(new MApplicationExtensionManager(interface)); - QObject::connect(extensionManager.data(), SIGNAL(extensionInstantiated(MApplicationExtensionInterface *)), q, SIGNAL(extensionInstantiated(MApplicationExtensionInterface *)), Qt::QueuedConnection); - QObject::connect(extensionManager.data(), SIGNAL(extensionRemoved(MApplicationExtensionInterface*)), q, SIGNAL(extensionRemoved(MApplicationExtensionInterface*)), Qt::QueuedConnection); + QObject::connect(extensionManager.data(), SIGNAL(extensionInstantiated(MApplicationExtensionInterface *)), q, SIGNAL(extensionInstantiated(MApplicationExtensionInterface *))); + QObject::connect(extensionManager.data(), SIGNAL(extensionRemoved(MApplicationExtensionInterface*)), q, SIGNAL(extensionRemoved(MApplicationExtensionInterface*))); QObject::connect(extensionManager.data(), SIGNAL(widgetCreated(QGraphicsWidget*, MDataStore&)), q, SLOT(addWidget(QGraphicsWidget*, MDataStore&))); QObject::connect(extensionManager.data(), SIGNAL(widgetRemoved(QGraphicsWidget*)), q, SLOT(removeWidget(QGraphicsWidget*))); } diff --git a/src/extensions/applicationextension/mapplicationextensionarea.h b/src/extensions/applicationextension/mapplicationextensionarea.h index a443a3ff..d068cee9 100644 --- a/src/extensions/applicationextension/mapplicationextensionarea.h +++ b/src/extensions/applicationextension/mapplicationextensionarea.h @@ -94,7 +94,9 @@ public: /*! * Initializes the application extension area. All setters introduced by - * this class must be called before the area is initialized. Initialization + * this class must be called before the area is initialized, and the + * signals must be connected, because calling init() will result in + * the extensions being created. Initialization * will fail if no interface name has been provided or if the area has * already been initialized. * diff --git a/src/extensions/applicationextension/mapplicationextensionareaview.cpp b/src/extensions/applicationextension/mapplicationextensionareaview.cpp index 5253a28a..c27ccdbf 100644 --- a/src/extensions/applicationextension/mapplicationextensionareaview.cpp +++ b/src/extensions/applicationextension/mapplicationextensionareaview.cpp @@ -38,8 +38,11 @@ void MApplicationExtensionAreaViewPrivate::init(MApplicationExtensionArea *contr { this->controller = controller; - layout = new QGraphicsLinearLayout(Qt::Vertical); + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); controller->setLayout(layout); + this->layout = layout; } void MApplicationExtensionAreaViewPrivate::addToLayout(QGraphicsWidget *widget, int index) diff --git a/src/extensions/applicationextension/mapplicationextensionmanager.cpp b/src/extensions/applicationextension/mapplicationextensionmanager.cpp index 9da4d619..637e493a 100644 --- a/src/extensions/applicationextension/mapplicationextensionmanager.cpp +++ b/src/extensions/applicationextension/mapplicationextensionmanager.cpp @@ -28,6 +28,7 @@ #include "mdesktopentry.h" #include "mextensionhandle.h" #include "mfiledatastore.h" +#include "msubdatastore.h" #include "mdebug.h" MApplicationExtensionManager::MApplicationExtensionManager(const QString &interface) : @@ -76,15 +77,34 @@ bool MApplicationExtensionManager::init() updateAvailableExtensions(APPLICATION_EXTENSION_DATA_DIR); // Start watching the application extensions directory for changes - connect(&watcher, SIGNAL(directoryChanged(const QString)), this, SLOT(updateAvailableExtensions(QString))); - watcher.addPath(APPLICATION_EXTENSION_DATA_DIR); - + connectSignals(); + desktopDirectoryWatcher.addPath(APPLICATION_EXTENSION_DATA_DIR); return true; } +void MApplicationExtensionManager::parseAndInstantiateExtension( + const QString& desktopFile, + QSet<QString>* currentExtensionsList) +{ + QSharedPointer<const MApplicationExtensionMetaData> + metadata(new MApplicationExtensionMetaData(desktopFile)); + if (metadata->isValid() && metadata->type() == "X-MeeGoApplicationExtension" && metadata->interface() == interface) { + if (currentExtensionsList != NULL) { + currentExtensionsList->insert(desktopFile); + } + if (!extensionMetaDatas.contains(desktopFile)) { + // This extension is a new one. Instantiate it + if (instantiateExtension(metadata)) { + extensionMetaDatas[desktopFile] = metadata; + } + } + } +} + void MApplicationExtensionManager::updateAvailableExtensions(const QString &path) { - QList<QString> currentExtensionsList; + disconnectSignals(); + QSet<QString> currentExtensionsList; QDir applicationExtensionsDir(path); if (applicationExtensionsDir.exists()) { @@ -92,33 +112,38 @@ void MApplicationExtensionManager::updateAvailableExtensions(const QString &path filter << "*.desktop"; foreach(const QString &fileName, applicationExtensionsDir.entryList(filter, QDir::Files)) { const QString desktopFile = QFileInfo(applicationExtensionsDir, fileName).absoluteFilePath(); - QSharedPointer<MApplicationExtensionMetaData> metadata(new MApplicationExtensionMetaData(desktopFile)); - if (metadata->isValid() && metadata->type() == "X-MeeGoApplicationExtension" && metadata->interface() == interface) { - currentExtensionsList.append(fileName); - - if (!extensionMetaDatas.contains(fileName)) { - // This extension is a new one. Instantiate it - if (instantiateExtension(*metadata.data())) { - extensionMetaDatas[fileName] = metadata; - } - } - } + parseAndInstantiateExtension(desktopFile, + ¤tExtensionsList); } - // Find what extensions got removed - QList<QString> toBeRemovedExtensions; + QSet<QString> toBeRemovedExtensions; MetaDataEntryHash::const_iterator itEnd = extensionMetaDatas.constEnd(); for (MetaDataEntryHash::const_iterator it = extensionMetaDatas.constBegin(); it != itEnd; ++it) { if (!currentExtensionsList.contains(it.key())) { - toBeRemovedExtensions.append(it.key()); + toBeRemovedExtensions.insert(it.key()); } } // Remove extensions that no longer exist foreach (const QString &fileName, toBeRemovedExtensions) { - removeExtension(*extensionMetaDatas[fileName].data()); - extensionMetaDatas.remove(fileName); + removeExtension(*extensionMetaDatas[fileName]); } } + connectSignals(); +} + +void MApplicationExtensionManager::updateExtension( + const MDesktopEntry &extensionData) +{ + const MApplicationExtensionMetaData* metadata = + dynamic_cast<const MApplicationExtensionMetaData*>(&extensionData); + if (!metadata) { + return; + } + disconnectSignals(); + QString fileName = metadata->fileName(); + removeExtension(*metadata); + parseAndInstantiateExtension(fileName, NULL); + connectSignals(); } bool MApplicationExtensionManager::isInProcess(const MApplicationExtensionMetaData &metaData) @@ -126,25 +151,28 @@ bool MApplicationExtensionManager::isInProcess(const MApplicationExtensionMetaDa return metaData.runnerBinary().isEmpty(); } -bool MApplicationExtensionManager::instantiateExtension(const MApplicationExtensionMetaData &metadata) +bool MApplicationExtensionManager::instantiateExtension(QSharedPointer<const MApplicationExtensionMetaData> &metadata) { bool success = false; - if (isInProcess(metadata)) { - if (metadata.fileName().indexOf(inProcessFilter) >= 0) { - success = instantiateInProcessExtension(metadata.extensionBinary()); + if (isInProcess(*metadata)) { + if (metadata->fileName().indexOf(inProcessFilter) >= 0) { + success = instantiateInProcessExtension(metadata); } } else { - if (metadata.fileName().indexOf(outOfProcessFilter) >= 0) { + if (metadata->fileName().indexOf(outOfProcessFilter) >= 0) { success = instantiateOutOfProcessExtension(metadata); } } - + if (success) { + extensionWatcher.addExtension(metadata); + } return success; } -bool MApplicationExtensionManager::instantiateInProcessExtension(const QString &binary) +bool MApplicationExtensionManager::instantiateInProcessExtension(QSharedPointer<const MApplicationExtensionMetaData> &metadata) { + QString binary = metadata->extensionBinary(); QPluginLoader loader(binary); QObject *object = loader.instance(); @@ -157,14 +185,16 @@ bool MApplicationExtensionManager::instantiateInProcessExtension(const QString & if (success) { QGraphicsWidget *widget = extension->widget(); if (widget) { - // Inform about the added extension widget - emit widgetCreated(widget, *extensionDataStore.data()); + QString tmp = metadata->fileName(); + QSharedPointer<MDataStore> dataStore = + createSubDataStore(*metadata); + inProcessDataStores[metadata.data()] = dataStore; + emit widgetCreated(widget, *dataStore); } + // Store the instantiated extension + inProcessExtensions[metadata.data()] = qMakePair(extension, widget); // Inform interested parties about the new extension emit extensionInstantiated(extension); - - // Store the instantiated extension - inProcessExtensions[binary] = qMakePair(extension, widget); } } } @@ -176,12 +206,15 @@ bool MApplicationExtensionManager::instantiateInProcessExtension(const QString & return success; } -bool MApplicationExtensionManager::instantiateOutOfProcessExtension(const MApplicationExtensionMetaData &metadata) +bool MApplicationExtensionManager::instantiateOutOfProcessExtension( + QSharedPointer<const MApplicationExtensionMetaData> &metadata) { MExtensionHandle *handle = new MExtensionHandle; - handle->init(metadata.runnerBinary(), metadata.fileName()); - outOfProcessHandles.insert(metadata.fileName(), handle); - emit widgetCreated(handle, *extensionDataStore.data()); + handle->init(metadata->runnerBinary(), metadata->fileName()); + outOfProcessHandles.insert(metadata.data(), handle); + QSharedPointer<MDataStore> dataStore = createSubDataStore(*metadata); + outOfProcessDataStores[metadata.data()] = dataStore; + emit widgetCreated(handle, *dataStore); return true; } @@ -194,35 +227,41 @@ QString MApplicationExtensionManager::dataPath() const void MApplicationExtensionManager::removeExtension(const MApplicationExtensionMetaData &metadata) { + QString fileName = metadata.fileName(); if (isInProcess(metadata)) { - removeInProcessExtension(metadata.extensionBinary()); + removeInProcessExtension(metadata); } else { removeOutOfProcessExtension(metadata); } + extensionMetaDatas.remove(fileName); + extensionWatcher.removeExtension(metadata.fileName()); } -void MApplicationExtensionManager::removeInProcessExtension(const QString &binary) +void MApplicationExtensionManager::removeInProcessExtension( + const MApplicationExtensionMetaData &metadata) { - if (inProcessExtensions.contains(binary)) { - InProcessExtensionData extension = inProcessExtensions.take(binary); + if (inProcessExtensions.contains(&metadata)) { + InProcessExtensionData extension = inProcessExtensions.take(&metadata); emit extensionRemoved(extension.first); if (extension.second) { emit widgetRemoved(extension.second); } + inProcessDataStores.remove(&metadata); delete extension.first; + QPluginLoader loader(metadata.extensionBinary()); + loader.unload(); } } void MApplicationExtensionManager::removeOutOfProcessExtension(const MApplicationExtensionMetaData &metadata) { QString desktopFileName = metadata.fileName(); - if (outOfProcessHandles.contains(desktopFileName)) { - MExtensionHandle *handle = outOfProcessHandles.take(desktopFileName); - if (handle) { - emit widgetRemoved(handle); - handle->kill(); - delete handle; - } + MExtensionHandle *handle = outOfProcessHandles.take(&metadata); + if (handle) { + emit widgetRemoved(handle); + handle->kill(); + outOfProcessDataStores.remove(&metadata); + delete handle; } } @@ -259,3 +298,41 @@ bool MApplicationExtensionManager::createDataStore() return false; } } + +QSharedPointer<MDataStore> MApplicationExtensionManager::createSubDataStore( + const MApplicationExtensionMetaData &metadata) +{ + return QSharedPointer<MDataStore>( + new MSubDataStore( + metadata.fileName().replace('/', '\\') + + QString("/"), *extensionDataStore)); +} + +void MApplicationExtensionManager::connectSignals() +{ + connect(&extensionWatcher, + SIGNAL(extensionChanged( + const MDesktopEntry &)), + this, + SLOT(updateExtension( + const MDesktopEntry &))); + connect(&desktopDirectoryWatcher, + SIGNAL(directoryChanged(const QString)), + this, + SLOT(updateAvailableExtensions(QString))); +} + +void MApplicationExtensionManager::disconnectSignals() +{ + disconnect(&extensionWatcher, + SIGNAL(extensionChanged( + const MDesktopEntry &)), + this, + SLOT(updateExtension( + const MDesktopEntry &))); + disconnect(&desktopDirectoryWatcher, + SIGNAL(directoryChanged(const QString)), + this, + SLOT(updateAvailableExtensions(QString))); +} + diff --git a/src/extensions/applicationextension/mapplicationextensionmanager.h b/src/extensions/applicationextension/mapplicationextensionmanager.h index 5eb80e1e..99acbe0b 100644 --- a/src/extensions/applicationextension/mapplicationextensionmanager.h +++ b/src/extensions/applicationextension/mapplicationextensionmanager.h @@ -24,8 +24,8 @@ #include <QFileSystemWatcher> #include <QHash> #include <QSharedPointer> -#include <QHash> #include <QRegExp> +#include "mextensionwatcher.h" class MApplicationExtensionMetaData; class MDataStore; @@ -124,13 +124,22 @@ private slots: */ void updateAvailableExtensions(const QString &path); + /*! + * \brief Slot for updating an extension when the files for the extension + * have been updated. + * \param extensionData the extension to update + */ + void updateExtension(const MDesktopEntry &extensionData); + private: //! Whether the manager has been initialized or not bool initialized; //! A file system watcher for the desktop entry file directory - QFileSystemWatcher watcher; + QFileSystemWatcher desktopDirectoryWatcher; + //! An extension watcher for observing modifications to the extensions + MExtensionWatcher extensionWatcher; //! The name of the interface extensions to be instantiated should implement QString interface; @@ -145,13 +154,19 @@ private: typedef QPair<MApplicationExtensionInterface*, QGraphicsWidget*> InProcessExtensionData; - //! Instantiated in-process extensions. A map from the shared library name to the extension instance. - QHash<QString, InProcessExtensionData> inProcessExtensions; + //! In-process extensions and datastores + QHash<const MApplicationExtensionMetaData*, InProcessExtensionData> inProcessExtensions; + + QHash<const MApplicationExtensionMetaData*, + QSharedPointer<MDataStore> > inProcessDataStores; - //! Hash of desktop file name versus the widget (handle) created - QHash<QString, MExtensionHandle*> outOfProcessHandles; + //! Ouf-of-process extensions and datastores + QHash<const MApplicationExtensionMetaData*, MExtensionHandle*> outOfProcessHandles; - typedef QHash<QString, QSharedPointer<MApplicationExtensionMetaData> > MetaDataEntryHash; + QHash<const MApplicationExtensionMetaData*, QSharedPointer<MDataStore> > + outOfProcessDataStores; + + typedef QHash<QString, QSharedPointer<const MApplicationExtensionMetaData> > MetaDataEntryHash; /*! * A container for application extension desktop entries with the correct application extension interface defined. * This container also only contains the entries that succeeded to instantiate. @@ -179,38 +194,67 @@ private: bool createDataStore(); /*! + * Creates a subdatastore for an extension + * \param metaData Metadata for the extension + */ + QSharedPointer<MDataStore> createSubDataStore( + const MApplicationExtensionMetaData &metaData); + /*! + * Connects the signals for the directory watcher and the extension + * watcher. + */ + void connectSignals(); + /*! + * Disconnects the signals for the directory watcher and the extension + * watcher. + */ + void disconnectSignals(); + + /*! + * Creates extension metadata and instantiates an extension + * if it isn't already instantiated. + * \param desktopFile Full path of the desktop file to parse. + * \param currentExtensionsList List of current extensions. + * Used by updateAvailableExtensions to keep track of which + * extensions exist and which need to be removed. + */ + void parseAndInstantiateExtension(const QString& desktopFile, + QSet<QString>* currentExtensionsList); + /*! * Instantiate an extension for an application extension metadata * \param metadata the metadata object of the extension * \return \c true if extension instantiated succesfully, \c false otherwise */ - bool instantiateExtension(const MApplicationExtensionMetaData &metadata); + bool instantiateExtension( + QSharedPointer<const MApplicationExtensionMetaData> &metadata); /*! * Instantiates an in process extension. - * - * \param binary the name of the in process extension binary + * \param metadata metadata for the extension * \return \c true if the instantiation succeeds, \c false otherwise */ - bool instantiateInProcessExtension(const QString &binary); + bool instantiateInProcessExtension( + QSharedPointer<const MApplicationExtensionMetaData> &metadata); /*! * Instantiate out of process extensions - * \param metadata for the extension + * \param metadata metadata for the extension * \return bool True if extension instantiated, else return false */ - bool instantiateOutOfProcessExtension(const MApplicationExtensionMetaData &metadata); + bool instantiateOutOfProcessExtension( + QSharedPointer<const MApplicationExtensionMetaData> &metadata); /*! * Removes an extension that was defined in the desktop entry given as a parameter. - * \param metadata the relevant metadata. + * \param metadata metadata for the extension */ void removeExtension(const MApplicationExtensionMetaData &metadata); /*! * Removes an in process extension that was loaded from the specified library. - * \param library the path name to the library + * \param metadata metadata for the extension */ - void removeInProcessExtension(const QString &library); + void removeInProcessExtension(const MApplicationExtensionMetaData &metadata); /*! * Removes an out of process extension that was loaded from the specified metadata diff --git a/src/extensions/applicationextension/mapplicationextensionmetadata.cpp b/src/extensions/applicationextension/mapplicationextensionmetadata.cpp index cd73f112..81d11d91 100644 --- a/src/extensions/applicationextension/mapplicationextensionmetadata.cpp +++ b/src/extensions/applicationextension/mapplicationextensionmetadata.cpp @@ -21,9 +21,9 @@ #include <QDir> #include <MDebug> -const QString ExtensionBinaryKey("X-MeeGoApplicationExtension/Extension"); -const QString IdentifierKey("X-MeeGoApplicationExtension/Identifier"); -const QString InterfaceKey("X-MeeGoApplicationExtension/Interface"); +const QString EXTENSION_BINARY_KEY("X-MeeGoApplicationExtension/Extension"); +const QString IDENTIFIER_KEY("X-MeeGoApplicationExtension/Identifier"); +const QString INTERFACE_KEY("X-MeeGoApplicationExtension/Interface"); MApplicationExtensionMetaData::MApplicationExtensionMetaData(const QString &fileName) : MDesktopEntry(fileName) { @@ -42,7 +42,7 @@ bool MApplicationExtensionMetaData::isValid() const // Loop through keys and check that all are found QStringList requiredKeys; - requiredKeys << ExtensionBinaryKey << InterfaceKey; + requiredKeys << EXTENSION_BINARY_KEY << INTERFACE_KEY; foreach(const QString &key, requiredKeys) { if (!contains(key)) { return false; @@ -80,7 +80,7 @@ QString MApplicationExtensionMetaData::runnerBinary() const QString MApplicationExtensionMetaData::extensionBinary() const { // Fetch the absolute file path and return it. - QFileInfo extension(QString(APPLICATION_EXTENSION_LIBS), value(ExtensionBinaryKey)); + QFileInfo extension(QString(APPLICATION_EXTENSION_LIBS), value(EXTENSION_BINARY_KEY)); if (extension.exists() && extension.isFile()) { return extension.absoluteFilePath(); } else { @@ -91,7 +91,7 @@ QString MApplicationExtensionMetaData::extensionBinary() const QString MApplicationExtensionMetaData::interface() const { - return value(InterfaceKey); + return value(INTERFACE_KEY); } QString MApplicationExtensionMetaData::extractLibraryName(const QString &libFileName) @@ -114,8 +114,8 @@ QString MApplicationExtensionMetaData::resourceIdentifier() const QString resourceId; QString binary = extensionBinary(); - if (contains(IdentifierKey)) { - resourceId = value(IdentifierKey); + if (contains(IDENTIFIER_KEY)) { + resourceId = value(IDENTIFIER_KEY); } else if (!binary.isNull()) { resourceId = extractLibraryName(binary); } else { diff --git a/src/extensions/applicationextension/mapplicationextensionmetadata.h b/src/extensions/applicationextension/mapplicationextensionmetadata.h index 6ee05884..f3651182 100644 --- a/src/extensions/applicationextension/mapplicationextensionmetadata.h +++ b/src/extensions/applicationextension/mapplicationextensionmetadata.h @@ -55,7 +55,7 @@ public: * file in that is given as a construction parameter. * \param filename Location of .desktop file to be read by constructed MApplicationExtensionMetaData instance. */ - MApplicationExtensionMetaData(const QString &filename); + explicit MApplicationExtensionMetaData(const QString &filename); /*! * Destructor diff --git a/src/extensions/applicationextension/mextensionareaview.cpp b/src/extensions/applicationextension/mextensionareaview.cpp index ad89c7c2..a1aadefb 100644 --- a/src/extensions/applicationextension/mextensionareaview.cpp +++ b/src/extensions/applicationextension/mextensionareaview.cpp @@ -24,6 +24,8 @@ #include "mdatastore.h" #include "mcontainer.h" +static const QString LAYOUT_INDEX = "layoutIndex"; + MExtensionAreaViewPrivate::MExtensionAreaViewPrivate() : controller(0), layout(0), @@ -80,8 +82,8 @@ void MExtensionAreaViewPrivate::updateData() // Change the data in the store if item is still valid and geometry has changed. if (centralWidget != NULL && dsMap->contains(centralWidget) && - (*dsMap)[centralWidget]->value("layoutIndex") != i) { - (*dsMap)[centralWidget]->createValue("layoutIndex", i); + (*dsMap)[centralWidget]->value(LAYOUT_INDEX) != i) { + (*dsMap)[centralWidget]->createValue(LAYOUT_INDEX, i); } } } @@ -114,7 +116,8 @@ void MExtensionAreaViewPrivate::updateLayout() bool alreadyInLayout = false; const int count = layout->count(); for (int i = 0; i < count; ++i) { - MContainer *theContainer = dynamic_cast<MContainer *>(layout->itemAt(i)); + MContainer *theContainer = + dynamic_cast<MContainer *>(layout->itemAt(i)); if (widget == theContainer->centralWidget()) { // Widget found from the layout, don't add again alreadyInLayout = true; @@ -131,21 +134,19 @@ void MExtensionAreaViewPrivate::updateLayout() if (container) { setContainerEnabled(*container, q->style()->containerMode()); } - - int layoutIndex = 0; - // Add widget to the layout policy - if (store->allKeys().contains("layoutIndex") && - store->value("layoutIndex").type() == QVariant::Int) { - layoutIndex = store->value("layoutIndex").toInt(); - addToLayout(container, layoutIndex); + int layoutIndex = 0; + bool layoutIndexFound = false; + int tmpIndex = + store->value(LAYOUT_INDEX).toInt(&layoutIndexFound); + if (layoutIndexFound) { + layoutIndex = tmpIndex; } else { layoutIndex = layout->count(); - addToLayout(container); } - + addToLayout(container, layoutIndex); // Write the layout data to the permanent store - store->createValue("layoutIndex", layoutIndex); + store->createValue(LAYOUT_INDEX, layoutIndex); } } } diff --git a/src/extensions/applicationextension/mextensionrunner.cpp b/src/extensions/applicationextension/mextensionrunner.cpp index 4cbebff0..805874df 100644 --- a/src/extensions/applicationextension/mextensionrunner.cpp +++ b/src/extensions/applicationextension/mextensionrunner.cpp @@ -167,7 +167,6 @@ bool MExtensionRunner::init(const QString &serverName) teardown(); return false; } - return true; } @@ -383,10 +382,7 @@ void MExtensionRunner::createAppletPixmap(Qt::HANDLE handle) pixmap = QPixmap::fromX11Pixmap(handle, QPixmap::ExplicitlyShared); #ifdef QT_OPENGL_LIB - // Try to use opengl to render directly to the pixmap - if (context != NULL) - delete context; - + // The QGLWidget takes the ownership of the context context = new QGLContext(QGLFormat::defaultFormat(), &pixmap); context->create(); if (context->isValid()) { diff --git a/src/extensions/extensions.pro b/src/extensions/extensions.pro index 3c5a58ce..4798d970 100644 --- a/src/extensions/extensions.pro +++ b/src/extensions/extensions.pro @@ -22,6 +22,9 @@ contains(DEFINES, HAVE_DBUS) { LIBS += -lmeegotouchviews -lmeegotouchsettings -lmeegotouchcore -SOURCES += mextensionslibrary.cpp +SOURCES += mextensionwatcher.cpp \ + mextensionslibrary.cpp + +HEADERS += mextensionwatcher.h include(../common_bot.pri) diff --git a/src/extensions/mashup/mashup/mappletinstancemanager.cpp b/src/extensions/mashup/mashup/mappletinstancemanager.cpp index 99f2f11f..2a9ec44d 100644 --- a/src/extensions/mashup/mashup/mappletinstancemanager.cpp +++ b/src/extensions/mashup/mashup/mappletinstancemanager.cpp @@ -33,6 +33,8 @@ #include "mscenemanager.h" #include "morientationtracker.h" #include "maction.h" +#include "mextensionwatcher.h" +#include <algorithm> const QString MAppletInstanceManager::PACKAGE_MANAGER_DBUS_SERVICE = "com.nokia.package_manager"; const QString MAppletInstanceManager::PACKAGE_MANAGER_DBUS_PATH = "/com/nokia/package_manager"; @@ -50,6 +52,7 @@ MAppletInstanceManager::~MAppletInstanceManager() { qDeleteAll(applets.values()); delete fileDataStore; + delete watcher; } void MAppletInstanceManager::init(const QString &mashupCanvasName, MDataStore *dataStore) @@ -57,6 +60,7 @@ void MAppletInstanceManager::init(const QString &mashupCanvasName, MDataStore *d this->applicationName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); this->mashupCanvasName = mashupCanvasName; this->dataStore = dataStore; + this->watcher = new MExtensionWatcher; if (dataStore == NULL) { // Create a file datastore if a data store was not provided @@ -75,6 +79,8 @@ void MAppletInstanceManager::init(const QString &mashupCanvasName, MDataStore *d // Connect to the system bus to receive the Package Manager signals QDBusConnection::systemBus().connect(QString(), PACKAGE_MANAGER_DBUS_PATH, PACKAGE_MANAGER_DBUS_INTERFACE, "OperationComplete", this, SLOT(operationComplete(QString, QString, QString))); + connect(watcher, SIGNAL(extensionChanged(const MDesktopEntry &)), + this, SLOT(updateApplet(const MDesktopEntry &))); } bool MAppletInstanceManager::restoreApplets() @@ -114,6 +120,29 @@ void MAppletInstanceManager::instantiateAppletFromPackage(const QString &package instantiateApplet(appletId); } +/*! + * A helper functor class for finding remaining applet instances + * after removing one instance + */ +struct FindAppletByFileName +{ + QString fileName_; + /** + * Constructs the functor + * \param fileName File name to compare against + */ + explicit FindAppletByFileName(const QString& fileName) + : fileName_(fileName){ + } + /** + * Compares an applet instance against the wanted file name + * \param data Instance to compare + */ + bool operator()(const MAppletInstanceData* data) { + return data->desktopFile == fileName_; + } +}; + bool MAppletInstanceManager::removeApplet(MAppletId appletId) { // Make sure the applet instance exists in this particular applet instance manager @@ -121,12 +150,20 @@ bool MAppletInstanceManager::removeApplet(MAppletId appletId) appletId.mashupCanvasName() == mashupCanvasName && applets.contains(appletId.instanceId())) { // Get the data for the applet MAppletInstanceData *data = applets.value(appletId.instanceId()); - + QString fileName = data->desktopFile; // Let interested parties know that the applet's widget should be removed emit appletRemoved(data->widget); // Remove the applet instance data removeAppletInstanceData(appletId); + + if (std::find_if(applets.constBegin(), applets.constEnd(), + FindAppletByFileName(fileName)) + == applets.constEnd()) { + // this was the last instance, remove from watcher + watcher->removeExtension(data->desktopFile); + } + return true; } @@ -169,21 +206,24 @@ bool MAppletInstanceManager::instantiateApplet(MAppletId appletId) QFile desktopFile(data->desktopFile); if ((!data->desktopFile.isEmpty() && desktopFile.exists()) || data->installationStatus == MAppletInstanceData::Installing) { // The desktop file exists, so the applet is installed or the applet was being installed: instantiate the applet - MAppletMetaData metadata(data->desktopFile); - if (metadata.isValid()) { + QSharedPointer<const MAppletMetaData> + metadata(new MAppletMetaData(data->desktopFile)); + if (metadata->isValid()) { // Check whether a runner is defined bool success; - if (metadata.runnerBinary().isEmpty()) { + if (metadata->runnerBinary().isEmpty()) { // Runner not defined: create an in-process applet - success = instantiateInProcessApplet(data, metadata); + // IN PROCESS APPLETS ARE NOT FULLY SUPPORTED AT THE MOMENT + success = instantiateInProcessApplet(data, *metadata); } else { // Runner is defined: create an out-of-process applet - success = instantiateOutOfProcessApplet(data, metadata); + success = instantiateOutOfProcessApplet(data, *metadata); } if (success) { // Notify that the applet placeholder instantiation is done emit appletInstantiated(data->widget, *data->mashupCanvasDataStore); + watcher->addExtension(metadata); return true; } } @@ -208,6 +248,26 @@ bool MAppletInstanceManager::instantiateApplet(MAppletId appletId) return false; } +void MAppletInstanceManager::updateApplet(const MDesktopEntry &updatedExtension) +{ + const MAppletMetaData* metadata = + dynamic_cast<const MAppletMetaData*>(&updatedExtension); + if (metadata->runnerBinary().isEmpty()) { + // Runner not defined: create an in-process applet + // IN PROCESS APPLETS ARE NOT FULLY SUPPORTED AT THE MOMENT + qWarning() << "In-process applet updates are not supported at the moment"; + } else { + AppletContainerIterator appletIterator(applets); + while (appletIterator.hasNext()) { + appletIterator.next(); + if (appletIterator.value()->desktopFile == metadata->fileName()) { + MAppletHandle *handle = dynamic_cast<MAppletHandle *>(appletIterator.value()->widget); + handle->reinit(); + } + } + } +} + bool MAppletInstanceManager::instantiateOutOfProcessApplet(MAppletInstanceData *data, const MAppletMetaData &metadata) { // Create an applet handle if one doesn't exist already @@ -245,6 +305,7 @@ bool MAppletInstanceManager::instantiateOutOfProcessApplet(MAppletInstanceData * return true; } +// IN PROCESS APPLETS ARE NOT FULLY SUPPORTED AT THE MOMENT bool MAppletInstanceManager::instantiateInProcessApplet(MAppletInstanceData *data, const MAppletMetaData &metadata) { MFileDataStore *instanceDataStore = new MFileDataStore(data->instanceDataFilePath); diff --git a/src/extensions/mashup/mashup/mappletinstancemanager.h b/src/extensions/mashup/mashup/mappletinstancemanager.h index 52e1067b..b00fc81b 100644 --- a/src/extensions/mashup/mashup/mappletinstancemanager.h +++ b/src/extensions/mashup/mashup/mappletinstancemanager.h @@ -32,6 +32,8 @@ class MAppletMetaData; class MAppletHandle; class MFileDataStore; class QDBusPendingCallWatcher; +class MExtensionWatcher; +class MDesktopEntry; //! \internal @@ -160,6 +162,14 @@ private slots: */ void receiveOperation(QDBusPendingCallWatcher *watcher); + /*! + * Tells us that we need to update the applet. Currently the \c watcher informs the manager + * that the update desktop file has changed + * + * \param appletData The applet that has changed. + */ + void updateApplet(const MDesktopEntry &appletData); + private: /*! * Initializes the instance manager. @@ -380,6 +390,9 @@ private: //! A map for keeping track of running applets AppletContainer applets; + //! The watcher used to monitor changes in the applets + MExtensionWatcher *watcher; + //! The last applet ID that used to be free MAppletId::AppletInstanceID lastAppletInstanceID; diff --git a/src/extensions/mextensionwatcher.cpp b/src/extensions/mextensionwatcher.cpp new file mode 100644 index 00000000..44464d84 --- /dev/null +++ b/src/extensions/mextensionwatcher.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** This file is part of libmeegotouch. +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#include "mextensionwatcher.h" +#include "mdesktopentry.h" +#include "mapplicationextensionmetadata.h" +#include <QFile> +#include <QStringList> + + +MExtensionWatcher::MExtensionWatcher() +{ + connect(&watcher, SIGNAL(fileChanged(const QString &)), this, SLOT(notifyDataChanged(const QString &))); +} + +MExtensionWatcher::~MExtensionWatcher() +{ +} + +void MExtensionWatcher::addExtension( + QSharedPointer<const MDesktopEntry> extension) +{ + QString fileName = extension->fileName(); + if (!extensionsToWatch.contains(fileName)) { + extensionsToWatch.insert(fileName, extension); + watcher.addPath(fileName); + } +} + +void MExtensionWatcher::removeExtension(const QString &fileName) +{ + extensionsToWatch.remove(fileName); +} + +void MExtensionWatcher::notifyDataChanged(const QString &path) const +{ + // If the file does not exist anymore no need to signal an update for it + // observation of the file removal is handled by the instance managers + if (!QFile::exists(path)) { + return; + } + QHash<QString, QSharedPointer<const MDesktopEntry> >::const_iterator + extension = extensionsToWatch.find(path); + if (extension != extensionsToWatch.constEnd()) { + emit extensionChanged(*extension.value()); + } + if (!watcher.files().contains(path)) { + // if the file is removed and recreated, we need to re-add + // the path to the watcher + watcher.addPath(path); + } +} diff --git a/src/extensions/mextensionwatcher.h b/src/extensions/mextensionwatcher.h new file mode 100644 index 00000000..bc0a227e --- /dev/null +++ b/src/extensions/mextensionwatcher.h @@ -0,0 +1,98 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** This file is part of libmeegotouch. +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MEXTENSIONWATCHER_H +#define MEXTENSIONWATCHER_H + +#include <QFileSystemWatcher> +#include <QHash> +#include <QSharedPointer> + +class MDesktopEntry; + +/*! + * \brief \c MExtensionWatcher provides means to watch if either a given + * applet or a application extension has been updated by the package manager. + * If the change happens a corresponding signal will be emitted. + * + * The user of this class is responsible for the lifecycle management of the + * watched entries. This class does not assume ownership of the items nor can + * it detect if they are deleted. The user must remove the item from this + * watcher before deleting the item. Otherwise desktop file modification + * notification leads to undefined behaviour, because the target item of the + * notification will not exist. + */ +class MExtensionWatcher : public QObject +{ + Q_OBJECT + +public: + /*! + * Constructs the watcher instance + */ + MExtensionWatcher(); + + + /*! + * Destroys the wathcer instance + */ + virtual ~MExtensionWatcher(); + + /*! + * Add an extension to the list of watched extensions. + * If the extension (its desktop entry) changes, + * a signal \see extensionChanged will be emitted. + * + * \param extension The extension to watch. + */ + void addExtension(QSharedPointer<const MDesktopEntry> extension); + + /*! + * Removes an extension from the list of watched extension + * + * \param fileName Name of the desktop file of the extension to + * remove + */ + void removeExtension(const QString &fileName); + +Q_SIGNALS: + + /*! + * Informs that an extension (its desktop file) has changed. + * + * \param extension The extension that has changed + */ + void extensionChanged(const MDesktopEntry &extension) const; + +private slots: + //! Listens in on the actual changes + void notifyDataChanged(const QString &path) const; + +private: + //! The watcher instance for observing changes to desktop files + mutable QFileSystemWatcher watcher; + //! The list of applets to watch + QHash<QString, QSharedPointer<const MDesktopEntry> > extensionsToWatch; + +#ifdef UNIT_TEST + friend class Ut_MExtensionWatcher; +#endif +}; + +#endif //MEXTENSIONWATCHER_H |