diff options
Diffstat (limited to 'SwifTools')
-rw-r--r-- | SwifTools/Notifier/GrowlNotifier.cpp | 97 | ||||
-rw-r--r-- | SwifTools/Notifier/GrowlNotifier.h | 34 | ||||
-rw-r--r-- | SwifTools/Notifier/Notifier.cpp | 14 | ||||
-rw-r--r-- | SwifTools/Notifier/Notifier.h | 30 | ||||
-rw-r--r-- | SwifTools/Notifier/NullNotifier.h | 17 | ||||
-rw-r--r-- | SwifTools/Notifier/SConscript | 13 | ||||
-rw-r--r-- | SwifTools/SConscript | 1 |
7 files changed, 206 insertions, 0 deletions
diff --git a/SwifTools/Notifier/GrowlNotifier.cpp b/SwifTools/Notifier/GrowlNotifier.cpp new file mode 100644 index 0000000..4c671ac --- /dev/null +++ b/SwifTools/Notifier/GrowlNotifier.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +// FIXME: Is it safe to pass boost::function<void()> by raw values? +// FIXME: Should we release the strings created in the constructor? + +#include <cassert> + +#include "Swiften/Base/ByteArray.h" +#include "SwifTools/Notifier/GrowlNotifier.h" + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +namespace { + struct Context { + Context() {} + Context(const boost::function<void()>& callback) : callback(callback) {} + + boost::function<void()> callback; + }; + + void notificationClicked(CFPropertyListRef growlContext) { + Context context; + + CFDataRef growlContextData = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) growlContext, 0); + assert(CFDataGetLength(growlContextData) == sizeof(Context)); + CFDataGetBytes(growlContextData, CFRangeMake(0, CFDataGetLength(growlContextData)), (UInt8*) &context); + + context.callback(); + } + + void notificationTimedout(CFPropertyListRef) { + } +} + +namespace Swift { + +GrowlNotifier::GrowlNotifier(const String& name) { + // All notifications + CFMutableArrayRef allNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactAvailable))); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactUnavailable))); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactStatusChange))); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(IncomingMessage))); + + // Default Notifications + CFMutableArrayRef defaultNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactAvailable))); + CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(IncomingMessage))); + + // Initialize delegate + InitGrowlDelegate(&delegate_); + delegate_.applicationName = SWIFTEN_STRING_TO_CFSTRING(name); + CFTypeRef keys[] = { GROWL_NOTIFICATIONS_ALL, GROWL_NOTIFICATIONS_DEFAULT }; + CFTypeRef values[] = { allNotifications, defaultNotifications }; + delegate_.registrationDictionary = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + delegate_.growlNotificationWasClicked = ¬ificationClicked; + delegate_.growlNotificationTimedOut = ¬ificationTimedout; + Growl_SetDelegate(&delegate_); +} + +void GrowlNotifier::showMessage(Type type, const String& subject, const String& description, const ByteArray& picture, boost::function<void()> callback) { + CFStringRef cfSubject = SWIFTEN_STRING_TO_CFSTRING(subject); + CFStringRef cfDescription = SWIFTEN_STRING_TO_CFSTRING(description); + CFStringRef cfName = SWIFTEN_STRING_TO_CFSTRING(typeToString(type)); + CFDataRef cfIcon = CFDataCreate( NULL, (UInt8*) picture.getData(), picture.getSize()); + + Context context(callback); + CFDataRef cfContextData[1]; + cfContextData[0] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &context, sizeof(Context)); + CFArrayRef cfContext = CFArrayCreate( kCFAllocatorDefault, (const void **) cfContextData, 1, &kCFTypeArrayCallBacks ); + CFRelease(cfContextData[0]); + + Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext(cfSubject, cfDescription, cfName, cfIcon, 0, false, cfContext); + + CFRelease(cfContext); + CFRelease(cfIcon); + CFRelease(cfName); + CFRelease(cfDescription); + CFRelease(cfSubject); +} + +String GrowlNotifier::typeToString(Type type) { + switch (type) { + case ContactAvailable: return "Contact Becomes Available"; + case ContactUnavailable: return "Contact Becomes Unavailable"; + case ContactStatusChange: return "Contact Changes Status"; + case IncomingMessage: return "Incoming Message"; + } + assert(false); + return ""; +} + +} diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h new file mode 100644 index 0000000..fab3b5e --- /dev/null +++ b/SwifTools/Notifier/GrowlNotifier.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <CoreFoundation/CoreFoundation.h> +#include <Growl/Growl.h> + +#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. + * TODO: Find out what the easiest way is to do this without a QApplication. + */ + class GrowlNotifier : public Notifier { + public: + GrowlNotifier(const String& name); + + virtual void showMessage(Type type, const String& subject, const String& description, const ByteArray& picture, boost::function<void()> callback); + + private: + String typeToString(Type type); + + private: + Growl_Delegate delegate_; + }; +} diff --git a/SwifTools/Notifier/Notifier.cpp b/SwifTools/Notifier/Notifier.cpp new file mode 100644 index 0000000..2c2cfe5 --- /dev/null +++ b/SwifTools/Notifier/Notifier.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "SwifTools/Notifier/Notifier.h" + +namespace Swift { + +Notifier::~Notifier() { +} + +} diff --git a/SwifTools/Notifier/Notifier.h b/SwifTools/Notifier/Notifier.h new file mode 100644 index 0000000..7eb09f4 --- /dev/null +++ b/SwifTools/Notifier/Notifier.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/function.hpp> + +#include "Swiften/Base/String.h" + +namespace Swift { + class Notifier { + public: + virtual ~Notifier(); + + enum Type { ContactAvailable, ContactUnavailable, ContactStatusChange, IncomingMessage }; + + /** + * Picture is a PNG image. + */ + virtual void showMessage( + Type type, + const String& subject, + const String& description, + const ByteArray& picture, + boost::function<void()> callback) = 0; + }; +} diff --git a/SwifTools/Notifier/NullNotifier.h b/SwifTools/Notifier/NullNotifier.h new file mode 100644 index 0000000..d278e4f --- /dev/null +++ b/SwifTools/Notifier/NullNotifier.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "SwifTools/Notifier/Notifier.h" + +namespace Swift { + class NullNotifier : public Notifier { + public: + virtual void showMessage(Type, const String&, const String&, const ByteArray&, boost::function<void()>) { + } + }; +} diff --git a/SwifTools/Notifier/SConscript b/SwifTools/Notifier/SConscript new file mode 100644 index 0000000..89fc31b --- /dev/null +++ b/SwifTools/Notifier/SConscript @@ -0,0 +1,13 @@ +Import("swiftools_env") + +sources = [ + "Notifier.cpp", + ] + +if swiftools_env.get("HAVE_GROWL", False) : + sources += [ + "GrowlNotifier.cpp", + ] + +objects = swiftools_env.StaticObject(sources) +swiftools_env.Append(SWIFTOOLS_OBJECTS = objects) diff --git a/SwifTools/SConscript b/SwifTools/SConscript index 2675b9f..6b9b727 100644 --- a/SwifTools/SConscript +++ b/SwifTools/SConscript @@ -48,6 +48,7 @@ if env["SCONS_STAGE"] == "build" : SConscript(dirs = [ "Dock", + "Notifier", "Idle/IdleQuerierTest", "Idle/UnitTest", "UnitTest" |