From 8d1699709aef18feb72aa8a94ce2d009a54d285a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 31 May 2008 00:07:32 +0000 Subject: [PATCH] * For operations that implicitly install a MIME type, we no longer send two notifications (install + update), but only the install notification. * When create_app_meta_mime() installs a new MIME type (app signature or supported type), it only sends the install notification, instead of install + one or more updates. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25730 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../mime/CreateAppMetaMimeThread.cpp | 30 ++- .../registrar/mime/CreateAppMetaMimeThread.h | 4 +- src/servers/registrar/mime/Database.cpp | 192 ++++++++++++++---- src/servers/registrar/mime/Database.h | 40 ++++ .../registrar/mime/MimeUpdateThread.cpp | 8 +- src/servers/registrar/mime/MimeUpdateThread.h | 7 +- .../registrar/mime/UpdateMimeInfoThread.cpp | 8 +- .../registrar/mime/UpdateMimeInfoThread.h | 2 +- 8 files changed, 239 insertions(+), 52 deletions(-) diff --git a/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp b/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp index 27de6e6dc4..b53007c338 100644 --- a/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp +++ b/src/servers/registrar/mime/CreateAppMetaMimeThread.cpp @@ -22,16 +22,19 @@ #include +#include "Database.h" + + namespace BPrivate { namespace Storage { namespace Mime { CreateAppMetaMimeThread::CreateAppMetaMimeThread(const char *name, - int32 priority, BMessenger managerMessenger, const entry_ref *root, - bool recursive, int32 force, BMessage *replyee) - : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, - replyee) + int32 priority, Database *database, BMessenger managerMessenger, + const entry_ref *root, bool recursive, int32 force, BMessage *replyee) + : MimeUpdateThread(name, priority, database, managerMessenger, root, + recursive, force, replyee) { } @@ -76,6 +79,8 @@ CreateAppMetaMimeThread::DoMimeUpdate(const entry_ref* ref, bool* _entryIsDir) if (status < B_OK) return status; + InstallNotificationDeferrer _(fDatabase, signature.String()); + if (!mime.IsInstalled()) mime.Install(); @@ -126,14 +131,23 @@ CreateAppMetaMimeThread::DoMimeUpdate(const entry_ref* ref, bool* _entryIsDir) } // Supported Types + bool setSupportedTypes = false; BMessage supportedTypes; if (status == B_OK && (fForce || typeNode.GetAttrInfo(kSupportedTypesAttr, &info) != B_OK)) { if (appInfo.GetSupportedTypes(&supportedTypes) == B_OK) - status = mime.SetSupportedTypes(&supportedTypes); + setSupportedTypes = true; } - // Icons for supported types + // defer notifications for supported types const char* type; + for (int32 i = 0; supportedTypes.FindString("types", i, &type) == B_OK; i++) + fDatabase->DeferInstallNotification(type); + + // set supported types + if (setSupportedTypes) + status = mime.SetSupportedTypes(&supportedTypes); + + // Icons for supported types for (int32 i = 0; supportedTypes.FindString("types", i, &type) == B_OK; i++) { // vector icon uint8* data = NULL; @@ -150,6 +164,10 @@ CreateAppMetaMimeThread::DoMimeUpdate(const entry_ref* ref, bool* _entryIsDir) status = mime.SetIconForType(type, &largeIcon, B_LARGE_ICON); } + // undefer notifications for supported types + for (int32 i = 0; supportedTypes.FindString("types", i, &type) == B_OK; i++) + fDatabase->UndeferInstallNotification(type); + return status; } diff --git a/src/servers/registrar/mime/CreateAppMetaMimeThread.h b/src/servers/registrar/mime/CreateAppMetaMimeThread.h index aec4b1cbb6..9f44fc0254 100644 --- a/src/servers/registrar/mime/CreateAppMetaMimeThread.h +++ b/src/servers/registrar/mime/CreateAppMetaMimeThread.h @@ -19,8 +19,8 @@ namespace Mime { class CreateAppMetaMimeThread : public MimeUpdateThread { public: CreateAppMetaMimeThread(const char *name, int32 priority, - BMessenger managerMessenger, const entry_ref *root, bool recursive, - int32 force, BMessage *replyee); + Database *database, BMessenger managerMessenger, const entry_ref *root, + bool recursive, int32 force, BMessage *replyee); status_t DoMimeUpdate(const entry_ref *entry, bool *entryIsDir); }; diff --git a/src/servers/registrar/mime/Database.cpp b/src/servers/registrar/mime/Database.cpp index c37f3f039b..dc5ab39653 100644 --- a/src/servers/registrar/mime/Database.cpp +++ b/src/servers/registrar/mime/Database.cpp @@ -10,16 +10,18 @@ #include "Database.h" -#include -#include -#include +#include +#include + +#include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -27,12 +29,10 @@ #include #include -#include - -#include -#include -#include -#include +#include +#include +#include +#include #include "MessageDeliverer.h" @@ -60,7 +60,10 @@ namespace Mime { /*! \brief Creates and initializes a Mime::Database object. */ Database::Database() - : fStatus(B_NO_INIT) + : + fStatus(B_NO_INIT), + fDeferredInstallNotificationsLocker("deferred install notifications"), + fDeferredInstallNotifications() { // Do some really minor error checking BEntry entry(kDatabaseDir.c_str()); @@ -200,8 +203,8 @@ Database::_SetStringValue(const char *type, int32 what, const char* attribute, if (status == B_OK) { if (didCreate) _SendInstallNotification(type); - - _SendMonitorUpdate(what, type, B_META_MIME_MODIFIED); + else + _SendMonitorUpdate(what, type, B_META_MIME_MODIFIED); } return status; @@ -259,7 +262,8 @@ Database::SetAttrInfo(const char *type, const BMessage *info) if (status == B_OK) { if (didCreate) _SendInstallNotification(type); - _SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED); + else + _SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED); } return status; @@ -325,9 +329,12 @@ Database::SetFileExtensions(const char *type, const BMessage *extensions) extensions, &didCreate); if (status == B_OK) { - if (didCreate) + if (didCreate) { _SendInstallNotification(type); - _SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_MODIFIED); + } else { + _SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, + B_META_MIME_MODIFIED); + } } return status; @@ -424,20 +431,22 @@ Database::SetIconForType(const char *type, const char *fileType, bool didCreate = false; status_t err = open_or_create_type(type, &node, &didCreate); - if (!err && didCreate) - _SendInstallNotification(type); + if (err != B_OK) + return err; if (!err) err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize); if (err >= 0) err = err == (ssize_t)attrSize ? (status_t)B_OK : (status_t)B_FILE_ERROR; - if (!err) { + if (didCreate) { + _SendInstallNotification(type); + } else if (!err) { if (fileType) { _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, (which == B_LARGE_ICON), B_META_MIME_MODIFIED); } else { - _SendMonitorUpdate(B_ICON_CHANGED, type, (which == B_LARGE_ICON), - B_META_MIME_MODIFIED); + _SendMonitorUpdate(B_ICON_CHANGED, type, + (which == B_LARGE_ICON), B_META_MIME_MODIFIED); } } return err; @@ -483,14 +492,16 @@ Database::SetIconForType(const char *type, const char *fileType, bool didCreate = false; status_t err = open_or_create_type(type, &node, &didCreate); - if (!err && didCreate) - _SendInstallNotification(type); + if (err != B_OK) + return err; if (!err) err = node.WriteAttr(attr.c_str(), attrType, 0, data, dataSize); if (err >= 0) err = err == (ssize_t)dataSize ? (status_t)B_OK : (status_t)B_FILE_ERROR; - if (!err) { + if (didCreate) { + _SendInstallNotification(type); + } else if (!err) { // TODO: extra notification for vector icons (currently // passing "true" for B_LARGE_ICON)? if (fileType) { @@ -542,10 +553,11 @@ Database::SetSnifferRule(const char *type, const char *rule) if (status == B_OK) status = fSnifferRules.SetSnifferRule(type, rule); - if (status == B_OK) { - if (didCreate) - _SendInstallNotification(type); - _SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_MODIFIED); + if (didCreate) { + _SendInstallNotification(type); + } else if (status == B_OK) { + _SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, + B_META_MIME_MODIFIED); } return status; @@ -593,16 +605,20 @@ Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSy &didCreate); // Notify the monitor if we created the type when we opened it - if (status == B_OK && didCreate) - _SendInstallNotification(type); + if (status != B_OK) + return status; // Update the supporting apps map if (status == B_OK) status = fSupportingApps.SetSupportedTypes(type, types, fullSync); // Notify the monitor - if (status == B_OK) - _SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_MODIFIED); + if (didCreate) { + _SendInstallNotification(type); + } else if (status == B_OK) { + _SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, + B_META_MIME_MODIFIED); + } return status; } @@ -1274,6 +1290,51 @@ Database::DeleteSupportedTypes(const char *type, bool fullSync) } +void +Database::DeferInstallNotification(const char* type) +{ + AutoLocker _(fDeferredInstallNotificationsLocker); + + // check, if already deferred + if (_FindDeferredInstallNotification(type)) + return; + + // add new + DeferredInstallNotification* notification + = new(std::nothrow) DeferredInstallNotification; + if (notification == NULL) + return; + + strlcpy(notification->type, type, sizeof(notification->type)); + notification->notify = false; + + if (!fDeferredInstallNotifications.AddItem(notification)) + delete notification; +} + + +void +Database::UndeferInstallNotification(const char* type) +{ + AutoLocker locker(fDeferredInstallNotificationsLocker); + + // check, if deferred at all + DeferredInstallNotification* notification + = _FindDeferredInstallNotification(type, true); + + locker.Unlock(); + + if (notification == NULL) + return; + + // notify, if requested + if (notification->notify) + _SendInstallNotification(notification->type); + + delete notification; +} + + //! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service status_t Database::_SendInstallNotification(const char *type) @@ -1305,7 +1366,10 @@ Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraTyp { BMessage msg(B_META_MIME_CHANGED); status_t err; - + + if (_CheckDeferredInstallNotification(which, type)) + return B_OK; + err = msg.AddInt32("be:which", which); if (!err) err = msg.AddString("be:type", type); @@ -1331,6 +1395,9 @@ status_t Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType, int32 action) { + if (_CheckDeferredInstallNotification(which, type)) + return B_OK; + BMessage msg(B_META_MIME_CHANGED); status_t err = msg.AddInt32("be:which", which); @@ -1356,6 +1423,9 @@ Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraTyp status_t Database::_SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action) { + if (_CheckDeferredInstallNotification(which, type)) + return B_OK; + BMessage msg(B_META_MIME_CHANGED); status_t err = msg.AddInt32("be:which", which); @@ -1379,6 +1449,9 @@ Database::_SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int3 status_t Database::_SendMonitorUpdate(int32 which, const char *type, int32 action) { + if (_CheckDeferredInstallNotification(which, type)) + return B_OK; + BMessage msg(B_META_MIME_CHANGED); status_t err = msg.AddInt32("be:which", which); @@ -1413,7 +1486,58 @@ Database::_SendMonitorUpdate(BMessage &msg) return err; } + +Database::DeferredInstallNotification* +Database::_FindDeferredInstallNotification(const char* type, bool remove) +{ + for (int32 i = 0; + DeferredInstallNotification* notification + = (DeferredInstallNotification*)fDeferredInstallNotifications + .ItemAt(i); i++) { + if (strcmp(type, notification->type) == 0) { + if (remove) + fDeferredInstallNotifications.RemoveItem(i); + return notification; + } + } + + return NULL; +} + + +bool +Database::_CheckDeferredInstallNotification(int32 which, const char* type) +{ + AutoLocker locker(fDeferredInstallNotificationsLocker); + + // check, if deferred at all + DeferredInstallNotification* notification + = _FindDeferredInstallNotification(type); + if (notification == NULL) + return false; + + if (which == B_MIME_TYPE_DELETED) { + // MIME type deleted -- if the install notification had been + // deferred, we don't send anything + if (notification->notify) { + fDeferredInstallNotifications.RemoveItem(notification); + delete notification; + return true; + } + } else if (which == B_MIME_TYPE_CREATED) { + // MIME type created -- defer notification + notification->notify = true; + return true; + } else { + // MIME type update -- don't send update, if deferred + if (notification->notify) + return true; + } + + return false; +} + + } // namespace Mime } // namespace Storage } // namespace BPrivate - diff --git a/src/servers/registrar/mime/Database.h b/src/servers/registrar/mime/Database.h index ba512776b6..c9ffbd16f0 100644 --- a/src/servers/registrar/mime/Database.h +++ b/src/servers/registrar/mime/Database.h @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include #include @@ -102,7 +104,16 @@ class Database { status_t DeleteSnifferRule(const char *type); status_t DeleteSupportedTypes(const char *type, bool fullSync); + // deferred notifications + void DeferInstallNotification(const char* type); + void UndeferInstallNotification(const char* type); + private: + struct DeferredInstallNotification { + char type[B_MIME_TYPE_LENGTH]; + bool notify; + }; + status_t _SetStringValue(const char *type, int32 what, const char* attribute, type_code attributeType, size_t maxLength, const char *value); @@ -120,6 +131,10 @@ class Database { int32 action); status_t _SendMonitorUpdate(BMessage &msg); + DeferredInstallNotification* _FindDeferredInstallNotification( + const char* type, bool remove = false); + bool _CheckDeferredInstallNotification(int32 which, const char* type); + private: status_t fStatus; std::set fMonitorMessengers; @@ -127,6 +142,31 @@ class Database { InstalledTypes fInstalledTypes; SnifferRules fSnifferRules; SupportingApps fSupportingApps; + + BLocker fDeferredInstallNotificationsLocker; + BList fDeferredInstallNotifications; +}; + +class InstallNotificationDeferrer { + public: + InstallNotificationDeferrer(Database* database, const char* type) + : + fDatabase(database), + fType(type) + { + if (fDatabase != NULL && fType != NULL) + fDatabase->DeferInstallNotification(fType); + } + + ~InstallNotificationDeferrer() + { + if (fDatabase != NULL && fType != NULL) + fDatabase->UndeferInstallNotification(fType); + } + + private: + Database* fDatabase; + const char* fType; }; } // namespace Mime diff --git a/src/servers/registrar/mime/MimeUpdateThread.cpp b/src/servers/registrar/mime/MimeUpdateThread.cpp index e671e17ac5..d68ea3cb94 100644 --- a/src/servers/registrar/mime/MimeUpdateThread.cpp +++ b/src/servers/registrar/mime/MimeUpdateThread.cpp @@ -49,9 +49,11 @@ namespace Mime { The message will be replied to at the end of the thread's execution. */ MimeUpdateThread::MimeUpdateThread(const char *name, int32 priority, - BMessenger managerMessenger, const entry_ref *root, bool recursive, - int32 force, BMessage *replyee) - : RegistrarThread(name, priority, managerMessenger), + Database *database, BMessenger managerMessenger, const entry_ref *root, + bool recursive, int32 force, BMessage *replyee) + : + RegistrarThread(name, priority, managerMessenger), + fDatabase(database), fRoot(root ? *root : entry_ref()), fRecursive(recursive), fForce(force), diff --git a/src/servers/registrar/mime/MimeUpdateThread.h b/src/servers/registrar/mime/MimeUpdateThread.h index adca70a977..ef6fa7f129 100644 --- a/src/servers/registrar/mime/MimeUpdateThread.h +++ b/src/servers/registrar/mime/MimeUpdateThread.h @@ -25,9 +25,11 @@ namespace BPrivate { namespace Storage { namespace Mime { +class Database; + class MimeUpdateThread : public RegistrarThread { public: - MimeUpdateThread(const char *name, int32 priority, + MimeUpdateThread(const char *name, int32 priority, Database *database, BMessenger managerMessenger, const entry_ref *root, bool recursive, int32 force, BMessage *replyee); virtual ~MimeUpdateThread(); @@ -37,7 +39,8 @@ public: protected: virtual status_t ThreadFunction(); virtual status_t DoMimeUpdate(const entry_ref *entry, bool *entryIsDir) = 0; - + + Database* fDatabase; const entry_ref fRoot; const bool fRecursive; const int32 fForce; diff --git a/src/servers/registrar/mime/UpdateMimeInfoThread.cpp b/src/servers/registrar/mime/UpdateMimeInfoThread.cpp index 9e2489cf49..d971070ba5 100644 --- a/src/servers/registrar/mime/UpdateMimeInfoThread.cpp +++ b/src/servers/registrar/mime/UpdateMimeInfoThread.cpp @@ -66,10 +66,10 @@ is_shared_object_mime_type(BMimeType &type) // constructor //! Creates a new UpdateMimeInfoThread object UpdateMimeInfoThread::UpdateMimeInfoThread(const char *name, int32 priority, - BMessenger managerMessenger, const entry_ref *root, bool recursive, - int32 force, BMessage *replyee) - : MimeUpdateThread(name, priority, managerMessenger, root, recursive, force, - replyee) + Database *database, BMessenger managerMessenger, const entry_ref *root, + bool recursive, int32 force, BMessage *replyee) + : MimeUpdateThread(name, priority, database, managerMessenger, root, + recursive, force, replyee) { } diff --git a/src/servers/registrar/mime/UpdateMimeInfoThread.h b/src/servers/registrar/mime/UpdateMimeInfoThread.h index 4ef861be1c..ffbd00df41 100644 --- a/src/servers/registrar/mime/UpdateMimeInfoThread.h +++ b/src/servers/registrar/mime/UpdateMimeInfoThread.h @@ -18,7 +18,7 @@ namespace Mime { class UpdateMimeInfoThread : public MimeUpdateThread { public: - UpdateMimeInfoThread(const char *name, int32 priority, + UpdateMimeInfoThread(const char *name, int32 priority, Database *database, BMessenger managerMessenger, const entry_ref *root, bool recursive, int32 force, BMessage *replyee); status_t DoMimeUpdate(const entry_ref *entry, bool *entryIsDir);