summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'SwifTools')
-rw-r--r--SwifTools/Notifier/GrowlNotifier.cpp97
-rw-r--r--SwifTools/Notifier/GrowlNotifier.h34
-rw-r--r--SwifTools/Notifier/Notifier.cpp14
-rw-r--r--SwifTools/Notifier/Notifier.h30
-rw-r--r--SwifTools/Notifier/NullNotifier.h17
-rw-r--r--SwifTools/Notifier/SConscript13
-rw-r--r--SwifTools/SConscript1
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 = &notificationClicked;
+ delegate_.growlNotificationTimedOut = &notificationTimedout;
+ 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"