summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-09-03 16:01:14 (GMT)
committerTobias Markmann <tm@ayena.de>2015-09-03 16:20:31 (GMT)
commitbe6aa6e81b44be67518731d67bb2b72268d351e8 (patch)
treeeaa06c5bf303e627db91f869adba0611da393255
parentb6ffd5a332b6b21fdba9937fa3a0274556a09cdf (diff)
downloadswift-be6aa6e81b44be67518731d67bb2b72268d351e8.zip
swift-be6aa6e81b44be67518731d67bb2b72268d351e8.tar.bz2
Initial support for OS X Notification Center
This implements basic support for OS X Notification Center notifications with simple banner notifications showing type, contact and message/presence information. A click on the notification opens the chat view to the contact. The Notification Center backend will be used on OS X if the Growl notification backend is not used. This code requires OS X version 10.8 or later. Test-Information: Tested presence and message notifications between multiple Swift accounts and instances on OS X 10.9.5. Change-Id: I7b9e2132cab25e086e0912191562cad8f4cbae38
-rw-r--r--SwifTools/Notifier/NotificationCenterNotifier.h38
-rw-r--r--SwifTools/Notifier/NotificationCenterNotifier.mm87
-rw-r--r--SwifTools/Notifier/NotificationCenterNotifierDelegate.h22
-rw-r--r--SwifTools/Notifier/NotificationCenterNotifierDelegate.mm26
-rw-r--r--SwifTools/Notifier/SConscript6
-rw-r--r--Swift/QtUI/QtSwift.cpp4
6 files changed, 183 insertions, 0 deletions
diff --git a/SwifTools/Notifier/NotificationCenterNotifier.h b/SwifTools/Notifier/NotificationCenterNotifier.h
new file mode 100644
index 0000000..0d43c5b
--- /dev/null
+++ b/SwifTools/Notifier/NotificationCenterNotifier.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <SwifTools/Notifier/Notifier.h>
+
+namespace Swift {
+
+/**
+ * @brief The NotificationCenterNotifier class implmenents the notification interface for the
+ * OS X Notification Center API.
+ */
+class NotificationCenterNotifier : public Notifier {
+public:
+ NotificationCenterNotifier();
+ virtual ~NotificationCenterNotifier();
+
+ virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void ()> callback);
+ virtual void purgeCallbacks();
+
+ /**
+ * @brief The handleUserNotificationActivated is called by the delegate, when a user activates/clicks on a notification.
+ * @param identifier The std::string UUID identifiying the notification.
+ */
+ void handleUserNotificationActivated(const std::string& identifier);
+
+private:
+ class Private;
+ boost::shared_ptr<Private> p;
+};
+
+}
diff --git a/SwifTools/Notifier/NotificationCenterNotifier.mm b/SwifTools/Notifier/NotificationCenterNotifier.mm
new file mode 100644
index 0000000..df092ff
--- /dev/null
+++ b/SwifTools/Notifier/NotificationCenterNotifier.mm
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <SwifTools/Notifier/NotificationCenterNotifier.h>
+
+#include <map>
+#include <string>
+
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/Log.h>
+
+#import <Cocoa/Cocoa.h>
+
+#include <SwifTools/Notifier/NotificationCenterNotifierDelegate.h>
+#include <SwifTools/Cocoa/CocoaUtil.h>
+
+namespace {
+ struct Context {
+ Context(const boost::function<void()>& callback) : callback(new boost::function<void()>(callback)) {
+ }
+
+ ~Context() {
+ delete callback;
+ }
+
+ boost::function<void()>* callback;
+ };
+}
+
+namespace Swift {
+
+class NotificationCenterNotifier::Private {
+ public:
+ std::map<std::string, boost::shared_ptr<Context> > callbacksForNotifications;
+ boost::intrusive_ptr<NotificationCenterNotifierDelegate> delegate;
+};
+
+NotificationCenterNotifier::NotificationCenterNotifier() {
+ p = boost::make_shared<Private>();
+ p->delegate = boost::intrusive_ptr<NotificationCenterNotifierDelegate>([[NotificationCenterNotifierDelegate alloc] init], false);
+ [p->delegate.get() setNotifier: this];
+
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate: p->delegate.get()];
+}
+
+NotificationCenterNotifier::~NotificationCenterNotifier() {
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate: nil];
+ p->callbacksForNotifications.clear();
+}
+
+void NotificationCenterNotifier::showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void ()> callback) {
+ NSUserNotification* notification = [[NSUserNotification alloc] init];
+ notification.title = STD2NSSTRING(typeToString(type));
+ notification.subtitle = STD2NSSTRING(subject);
+ notification.informativeText = STD2NSSTRING(description);
+ notification.contentImage = [[NSImage alloc] initWithContentsOfFile: STD2NSSTRING(picture.string())];
+
+ // The OS X Notification Center API does not allow to attach custom data, like a pointer to a callback function,
+ // to the NSUserNotification object. Therefore we maintain a mapping from a NSUserNotification instance's identification
+ // to their respective callbacks.
+ notification.identifier = [[NSUUID UUID] UUIDString];
+
+ /// \todo Currently the elements are only removed on application exit. Ideally the notifications not required anymore
+ /// are removed from the map; e.g. when visiting a chat view, all notifications from that view can be removed from
+ /// the map and the NSUserNotificationCenter.
+ p->callbacksForNotifications[NS2STDSTRING(notification.identifier)] = boost::make_shared<Context>(callback);
+ [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+}
+
+void NotificationCenterNotifier::purgeCallbacks() {
+ p->callbacksForNotifications.clear();
+}
+
+void NotificationCenterNotifier::handleUserNotificationActivated(const std::string& identifier) {
+ if (p->callbacksForNotifications.find(identifier) != p->callbacksForNotifications.end()) {
+ (*p->callbacksForNotifications[identifier]->callback)();
+ }
+ else {
+ SWIFT_LOG(warning) << "Missing callback entry for activated notification. The activate notification may come from another instance." << std::endl;
+ }
+}
+
+}
diff --git a/SwifTools/Notifier/NotificationCenterNotifierDelegate.h b/SwifTools/Notifier/NotificationCenterNotifierDelegate.h
new file mode 100644
index 0000000..ea8fae0
--- /dev/null
+++ b/SwifTools/Notifier/NotificationCenterNotifierDelegate.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+namespace Swift {
+ class NotificationCenterNotifier;
+}
+
+@interface NotificationCenterNotifierDelegate : NSObject<NSUserNotificationCenterDelegate> {
+}
+
+@property (nonatomic) Swift::NotificationCenterNotifier* notifier;
+
+- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
+
+@end
diff --git a/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm b/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm
new file mode 100644
index 0000000..617619c
--- /dev/null
+++ b/SwifTools/Notifier/NotificationCenterNotifierDelegate.mm
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#import "SwifTools/Notifier/NotificationCenterNotifierDelegate.h"
+
+#include <string>
+
+#include <SwifTools/Cocoa/CocoaUtil.h>
+#include <SwifTools/Notifier/NotificationCenterNotifier.h>
+
+@implementation NotificationCenterNotifierDelegate
+
+using namespace Swift;
+
+@synthesize notifier;
+
+- (void)userNotificationCenter:(NSUserNotificationCenter *) center didActivateNotification:(NSUserNotification *)notification {
+ (void)center;
+ std::string identifier = NS2STDSTRING(notification.identifier);
+ notifier->handleUserNotificationActivated(identifier);
+}
+
+@end
diff --git a/SwifTools/Notifier/SConscript b/SwifTools/Notifier/SConscript
index 98b5400..e60937b 100644
--- a/SwifTools/Notifier/SConscript
+++ b/SwifTools/Notifier/SConscript
@@ -11,6 +11,12 @@ if swiftools_env.get("HAVE_GROWL", False) :
"GrowlNotifier.mm",
"GrowlNotifierDelegate.mm",
]
+elif myenv["PLATFORM"] == "darwin" :
+ sources += [
+ "NotificationCenterNotifier.mm",
+ "NotificationCenterNotifierDelegate.mm",
+ ]
+
if swiftools_env.get("HAVE_SNARL", False) :
myenv.MergeFlags(myenv["SNARL_FLAGS"])
sources += [
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index 6d8ac7b..756f530 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -56,6 +56,8 @@
#include <SwifTools/Notifier/GrowlNotifier.h>
#elif defined(SWIFTEN_PLATFORM_LINUX)
#include <Swift/QtUI/FreeDesktopNotifier.h>
+#elif defined(SWIFTEN_PLATFORM_MACOSX)
+#include <SwifTools/Notifier/NotificationCenterNotifier.h>
#else
#include <SwifTools/Notifier/NullNotifier.h>
#endif
@@ -196,6 +198,8 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
notifier_ = new WindowsNotifier(SWIFT_APPLICATION_NAME, applicationPathProvider_->getResourcePath("/images/logo-icon-32.png"), systemTray->getQSystemTrayIcon());
#elif defined(SWIFTEN_PLATFORM_LINUX)
notifier_ = new FreeDesktopNotifier(SWIFT_APPLICATION_NAME);
+#elif defined(SWIFTEN_PLATFORM_MACOSX)
+ notifier_ = new NotificationCenterNotifier();
#else
notifier_ = new NullNotifier();
#endif