From c83da56f6c93db3dc8040be1137fd40a08bf4132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Fri, 9 Mar 2012 12:22:00 +0100 Subject: Handle double growl callbacks. diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct index 1412b56..b3d3c8f 100644 --- a/BuildTools/SCons/SConstruct +++ b/BuildTools/SCons/SConstruct @@ -242,7 +242,7 @@ if env["PLATFORM"] == "darwin" : growl_env = conf_env.Clone() growl_env.MergeFlags(growl_flags) conf = Configure(growl_env, custom_tests = { "CheckObjCHeader" : checkObjCHeader }) - if False and conf.CheckObjCHeader("Growl/Growl.h") : + if conf.CheckObjCHeader("Growl/Growl.h") : env["HAVE_GROWL"] = 1 env["GROWL_FLAGS"] = growl_flags env["GROWL_FRAMEWORK"] = "/Library/Frameworks/Growl.framework" diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h index cb0d089..f4e6803 100644 --- a/SwifTools/Notifier/GrowlNotifier.h +++ b/SwifTools/Notifier/GrowlNotifier.h @@ -20,6 +20,7 @@ namespace Swift { class GrowlNotifier : public Notifier { public: GrowlNotifier(const std::string& name); + ~GrowlNotifier(); virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function callback); virtual bool isExternallyConfigured() const; diff --git a/SwifTools/Notifier/GrowlNotifier.mm b/SwifTools/Notifier/GrowlNotifier.mm index cb4790e..31eabd3 100644 --- a/SwifTools/Notifier/GrowlNotifier.mm +++ b/SwifTools/Notifier/GrowlNotifier.mm @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -27,6 +28,7 @@ namespace Swift { class GrowlNotifier::Private { public: + std::set pendingNotifications; boost::intrusive_ptr delegate; }; @@ -55,12 +57,23 @@ GrowlNotifier::GrowlNotifier(const std::string& name) { [GrowlApplicationBridge setGrowlDelegate: p->delegate.get()]; } +GrowlNotifier::~GrowlNotifier() { + [GrowlApplicationBridge setGrowlDelegate: nil]; + foreach (Context* context, p->pendingNotifications) { + delete context; + } + p->pendingNotifications.clear(); +} + void GrowlNotifier::showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picturePath, boost::function callback) { ByteArray picture; readByteArrayFromFile(picture, picturePath.string()); Context* context = new Context(callback); - + // Growl sometimes sends timeout notifications twice for the same message. We therefore need + // to keep track of which ones have already been processed. + p->pendingNotifications.insert(context); + [GrowlApplicationBridge notifyWithTitle: STD2NSSTRING(subject) description: STD2NSSTRING(description) @@ -73,14 +86,19 @@ void GrowlNotifier::showMessage(Type type, const std::string& subject, const std void GrowlNotifier::handleNotificationClicked(void* rawData) { Context* context = *(Context**) [((NSData*) rawData) bytes]; - if (!context->callback->empty()) { - (*context->callback)(); + if (p->pendingNotifications.erase(context) > 0) { + if (!context->callback->empty()) { + (*context->callback)(); + } + delete context; } - delete context; } void GrowlNotifier::handleNotificationTimedOut(void* rawData) { - delete *(Context**) [((NSData*) rawData) bytes]; + Context* context = *(Context**) [((NSData*) rawData) bytes]; + if (p->pendingNotifications.erase(context) > 0) { + delete context; + } } bool GrowlNotifier::isExternallyConfigured() const { -- cgit v0.10.2-6-g49f6