diff options
-rw-r--r-- | BuildTools/SCons/SConstruct | 2 | ||||
-rw-r--r-- | SwifTools/Notifier/GrowlNotifier.h | 1 | ||||
-rw-r--r-- | SwifTools/Notifier/GrowlNotifier.mm | 28 |
3 files changed, 25 insertions, 6 deletions
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<void()> 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 <SwifTools/Notifier/GrowlNotifier.h> #include <boost/smart_ptr/make_shared.hpp> +#include <set> #include <SwifTools/Notifier/GrowlNotifierDelegate.h> #include <SwifTools/Cocoa/CocoaUtil.h> @@ -27,6 +28,7 @@ namespace Swift { class GrowlNotifier::Private { public: + std::set<Context*> pendingNotifications; boost::intrusive_ptr<GrowlNotifierDelegate> 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<void()> 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 { |