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 @@ -210,71 +210,71 @@ if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :  			env["HAVE_GCONF"] = 1  			env["GCONF_FLAGS"] = {  				"LIBS": gconf_env["LIBS"],  				"CCFLAGS": gconf_env["CCFLAGS"],  				"CPPPATH": gconf_env["CPPPATH"],  				"CPPDEFINES": gconf_env.get("CPPDEFINES", []),  			}  	conf.Finish()  # Sparkle  env["HAVE_SPARKLE"] = 0  if env["PLATFORM"] == "darwin" :  	sparkle_flags = {  			"FRAMEWORKPATH": ["/Library/Frameworks"],  			"FRAMEWORKS": ["Sparkle"]  		}  	sparkle_env = conf_env.Clone()  	sparkle_env.MergeFlags(sparkle_flags)  	conf = Configure(sparkle_env, custom_tests = { "CheckObjCHeader" : checkObjCHeader })  	if conf.CheckObjCHeader("Sparkle/Sparkle.h") :  		env["HAVE_SPARKLE"] = 1  		env["SPARKLE_FLAGS"] = sparkle_flags  		env["SPARKLE_FRAMEWORK"] = "/Library/Frameworks/Sparkle.framework"  	conf.Finish()  # Growl  env["HAVE_GROWL"] = 0  if env["PLATFORM"] == "darwin" :  	growl_flags = {  			"FRAMEWORKPATH": ["/Library/Frameworks"],  			"FRAMEWORKS": ["Growl"]  		}  	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"  	conf.Finish()  # Snarl  if env["PLATFORM"] == "win32" :  	env["HAVE_SNARL"] = True  # LibXML  conf = Configure(conf_env, custom_tests = {"CheckVersion": CheckVersion})  if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") :  #and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623) :  	env["HAVE_LIBXML"] = 1  	env["LIBXML_FLAGS"] = { "LIBS": ["xml2"] }  conf.Finish()  if not env.get("HAVE_LIBXML", 0) :  	libxml_env = conf_env.Clone()  	libxml_env.Append(CPPPATH = ["/usr/include/libxml2"])  	conf = Configure(libxml_env, custom_tests = {"CheckVersion": CheckVersion})  	if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") :  #	and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623):  		env["HAVE_LIBXML"] = 1  		env["LIBXML_FLAGS"] = { "CPPPATH": ["/usr/include/libxml2"], "LIBS": ["xml2"] }  	conf.Finish()  # Expat  if not env.get("HAVE_LIBXML",0) :  	expat_conf_env = conf_env.Clone()  	expat_flags = {}  	if env.get("expat_libdir", None) :  		expat_flags["LIBPATH"] = [env["expat_libdir"]]  	if env.get("expat_includedir", None) :  		expat_flags["CPPPATH"] = [env["expat_includedir"]] 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 @@ -1,35 +1,36 @@  /*   * Copyright (c) 2010-2011 Remko Tronçon   * Licensed under the GNU General Public License v3.   * See Documentation/Licenses/GPLv3.txt for more information.   */  #pragma once  #include <boost/filesystem/fstream.hpp>  #include <SwifTools/Notifier/Notifier.h>  namespace Swift {  	/**  	 * Preconditions for using growlnotifier:  	 * - Must be part a bundle.  	 * - The Carbon/Cocoa application loop must be running (e.g. through QApplication)  	 *   such that notifications are coming through.  	 */  	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;  			// Called by the delegate. Don't call.  			void handleNotificationClicked(void* data);  			void handleNotificationTimedOut(void* data);  		private:  			class Private;  			boost::shared_ptr<Private> p;  	};  } 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 @@ -1,90 +1,108 @@  /*   * Copyright (c) 2010-2011 Remko Tronçon   * Licensed under the GNU General Public License v3.   * See Documentation/Licenses/GPLv3.txt for more information.   */  #include <SwifTools/Notifier/GrowlNotifier.h>  #include <boost/smart_ptr/make_shared.hpp> +#include <set>  #include <SwifTools/Notifier/GrowlNotifierDelegate.h>  #include <SwifTools/Cocoa/CocoaUtil.h>  #include <Swiften/Base/foreach.h>  #include <Swiften/Base/ByteArray.h>  #pragma GCC diagnostic ignored "-Wold-style-cast"  namespace {  	struct Context {  		Context(const boost::function<void()>& callback) : callback(new boost::function<void()>(callback)) {}  		boost::function<void()>* callback;  	};  }  namespace Swift {  class GrowlNotifier::Private {  	public: +		std::set<Context*> pendingNotifications;  		boost::intrusive_ptr<GrowlNotifierDelegate> delegate;  };  GrowlNotifier::GrowlNotifier(const std::string& name) {  	p = boost::make_shared<Private>();  	p->delegate = boost::intrusive_ptr<GrowlNotifierDelegate>([[GrowlNotifierDelegate alloc] init], false);  	p->delegate.get().name = STD2NSSTRING(name);  	NSMutableArray* allNotifications = [[NSMutableArray alloc] init];  	foreach(Type type, getAllTypes()) {  		[allNotifications addObject: STD2NSSTRING(typeToString(type))];  	}  	NSMutableArray* defaultNotifications = [[NSMutableArray alloc] init];  	foreach(Type type, getDefaultTypes()) {  		[defaultNotifications addObject: STD2NSSTRING(typeToString(type))];  	}  	p->delegate.get().registrationDictionary = [[[NSDictionary alloc]   			initWithObjects: [NSArray arrayWithObjects: allNotifications, defaultNotifications, nil]   			forKeys: [NSArray arrayWithObjects: GROWL_NOTIFICATIONS_ALL, GROWL_NOTIFICATIONS_DEFAULT, nil]] autorelease];  	[allNotifications release];  	[defaultNotifications release];  	[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)  		notificationName: STD2NSSTRING(typeToString(type))  		iconData: [NSData dataWithBytes: vecptr(picture) length: picture.size()]  		priority: 0  		isSticky: NO  		clickContext: [NSData dataWithBytes: &context length: sizeof(context)]];  }  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 {  	return ![GrowlApplicationBridge isMistEnabled];  }  }  | 
 Swift