summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SwifTools/Cocoa/CocoaUtil.h24
-rw-r--r--SwifTools/Notifier/GrowlNotifier.cpp99
-rw-r--r--SwifTools/Notifier/GrowlNotifier.h11
-rw-r--r--SwifTools/Notifier/GrowlNotifier.mm84
-rw-r--r--SwifTools/Notifier/GrowlNotifierDelegate.h28
-rw-r--r--SwifTools/Notifier/GrowlNotifierDelegate.mm34
-rw-r--r--SwifTools/Notifier/SConscript3
7 files changed, 179 insertions, 104 deletions
diff --git a/SwifTools/Cocoa/CocoaUtil.h b/SwifTools/Cocoa/CocoaUtil.h
new file mode 100644
index 0000000..55fc325
--- /dev/null
+++ b/SwifTools/Cocoa/CocoaUtil.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+// Conversion utilities
+#define NS2STDSTRING(a) (a == nil ? std::string() : std::string([a cStringUsingEncoding:NSUTF8StringEncoding]))
+#define STD2NSSTRING(a) [NSString stringWithCString:a.c_str() encoding:NSUTF8StringEncoding]
+
+// Intrusive pointer for NSObjects
+#include <boost/intrusive_ptr.hpp>
+
+namespace boost {
+ inline void intrusive_ptr_add_ref(NSObject* object) {
+ [object retain];
+ }
+
+ inline void intrusive_ptr_release(NSObject* object) {
+ [object release];
+ }
+}
diff --git a/SwifTools/Notifier/GrowlNotifier.cpp b/SwifTools/Notifier/GrowlNotifier.cpp
deleted file mode 100644
index d83634d..0000000
--- a/SwifTools/Notifier/GrowlNotifier.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-// FIXME: Should we release the strings created in the constructor?
-
-#include <cassert>
-
-#include <Swiften/Base/String.h>
-#include <Swiften/Base/ByteArray.h>
-#include <SwifTools/Notifier/GrowlNotifier.h>
-#include <Swiften/Base/foreach.h>
-
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-namespace {
- struct Context {
- Context() : callback(0) {}
- Context(const boost::function<void()>& callback) : callback(new boost::function<void()>(callback)) {}
-
- boost::function<void()>* callback;
- };
-
- void processNotification(CFPropertyListRef growlContext, bool activateCallback) {
- Context context;
-
- CFDataRef growlContextData = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) growlContext, 0);
- assert(CFDataGetLength(growlContextData) == sizeof(Context));
- CFDataGetBytes(growlContextData, CFRangeMake(0, CFDataGetLength(growlContextData)), (UInt8*) &context);
-
- if (activateCallback && !context.callback->empty()) {
- (*context.callback)();
- }
- delete context.callback;
- }
-
- void notificationClicked(CFPropertyListRef growlContext) {
- processNotification(growlContext, true);
- }
-
- void notificationTimedout(CFPropertyListRef growlContext) {
- processNotification(growlContext, false);
- }
-}
-
-namespace Swift {
-
-GrowlNotifier::GrowlNotifier(const std::string& name) {
- // All notifications
- CFMutableArrayRef allNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- foreach(Type type, getAllTypes()) {
- CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(type)));
- }
-
- // Default Notifications
- CFMutableArrayRef defaultNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- foreach(Type type, getDefaultTypes()) {
- CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(type)));
- }
-
- // 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 = &notificationClicked;
- delegate_.growlNotificationTimedOut = &notificationTimedout;
- Growl_SetDelegate(&delegate_);
-}
-
-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());
-
- 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*) vecptr(picture), picture.size());
-
- 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);
-}
-
-}
diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h
index e2686e8..ffd717a 100644
--- a/SwifTools/Notifier/GrowlNotifier.h
+++ b/SwifTools/Notifier/GrowlNotifier.h
@@ -1,13 +1,11 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * 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 <CoreFoundation/CoreFoundation.h>
-#include <Growl/Growl.h>
#include <boost/filesystem/fstream.hpp>
#include <SwifTools/Notifier/Notifier.h>
@@ -24,8 +22,13 @@ namespace Swift {
GrowlNotifier(const std::string& name);
virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback);
+
+ // Called by the delegate. Don't call.
+ void handleNotificationClicked(void* data);
+ void handleNotificationTimedOut(void* data);
private:
- Growl_Delegate delegate_;
+ class Private;
+ boost::shared_ptr<Private> p;
};
}
diff --git a/SwifTools/Notifier/GrowlNotifier.mm b/SwifTools/Notifier/GrowlNotifier.mm
new file mode 100644
index 0000000..108259a
--- /dev/null
+++ b/SwifTools/Notifier/GrowlNotifier.mm
@@ -0,0 +1,84 @@
+/*
+ * 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 <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:
+ 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];
+
+ [GrowlApplicationBridge setGrowlDelegate: p->delegate.get()];
+}
+
+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* contextPtr = new Context(callback);
+ NSData* context = [NSData dataWithBytes: &contextPtr length: sizeof(contextPtr)];
+
+ [GrowlApplicationBridge
+ notifyWithTitle: STD2NSSTRING(subject)
+ description: STD2NSSTRING(description)
+ notificationName: STD2NSSTRING(typeToString(type))
+ iconData: [NSData dataWithBytes: vecptr(picture) length: picture.size()]
+ priority: 0
+ isSticky: NO
+ clickContext: context];
+}
+
+void GrowlNotifier::handleNotificationClicked(void* rawData) {
+ Context* context = *(Context**) [((NSData*) rawData) bytes];
+ if (!context->callback->empty()) {
+ (*context->callback)();
+ }
+ delete context;
+}
+
+void GrowlNotifier::handleNotificationTimedOut(void* rawData) {
+ delete *(Context**) [((NSData*) rawData) bytes];
+}
+
+}
diff --git a/SwifTools/Notifier/GrowlNotifierDelegate.h b/SwifTools/Notifier/GrowlNotifierDelegate.h
new file mode 100644
index 0000000..7a556cc
--- /dev/null
+++ b/SwifTools/Notifier/GrowlNotifierDelegate.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#import <Growl/Growl.h>
+
+namespace Swift {
+ class GrowlNotifier;
+}
+
+@interface GrowlNotifierDelegate : NSObject<GrowlApplicationBridgeDelegate> {
+ Swift::GrowlNotifier* notifier;
+ NSString* name;
+ NSDictionary* registrationDictionary;
+}
+
+@property (nonatomic, retain) NSDictionary* registrationDictionary;
+@property (nonatomic, copy) NSString* name;
+
+- (NSDictionary*) registrationDictionaryForGrowl;
+- (NSString *) applicationNameForGrowl;
+- (void) growlNotificationWasClicked: (id) clickContext;
+- (void) growlNotificationTimedOut: (id) clickContext;
+
+
+@end
diff --git a/SwifTools/Notifier/GrowlNotifierDelegate.mm b/SwifTools/Notifier/GrowlNotifierDelegate.mm
new file mode 100644
index 0000000..c7f725f
--- /dev/null
+++ b/SwifTools/Notifier/GrowlNotifierDelegate.mm
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#import "GrowlNotifierDelegate.h"
+
+#include <SwifTools/Notifier/GrowlNotifier.h>
+
+@implementation GrowlNotifierDelegate;
+
+@synthesize registrationDictionary;
+@synthesize name;
+
+using namespace Swift;
+
+- (NSString *) applicationNameForGrowl {
+ return name;
+}
+
+- (NSDictionary*) registrationDictionaryForGrowl {
+ return registrationDictionary;
+}
+
+- (void) growlNotificationWasClicked: (id) clickContext {
+ notifier->handleNotificationClicked(clickContext);
+}
+
+- (void) growlNotificationTimedOut: (id) clickContext {
+ notifier->handleNotificationTimedOut(clickContext);
+}
+
+@end
diff --git a/SwifTools/Notifier/SConscript b/SwifTools/Notifier/SConscript
index 9ad2fd7..98b5400 100644
--- a/SwifTools/Notifier/SConscript
+++ b/SwifTools/Notifier/SConscript
@@ -8,7 +8,8 @@ sources = [
if swiftools_env.get("HAVE_GROWL", False) :
sources += [
- "GrowlNotifier.cpp",
+ "GrowlNotifier.mm",
+ "GrowlNotifierDelegate.mm",
]
if swiftools_env.get("HAVE_SNARL", False) :
myenv.MergeFlags(myenv["SNARL_FLAGS"])