diff options
author | Tobias Markmann <tm@ayena.de> | 2015-09-03 16:01:14 (GMT) |
---|---|---|
committer | Tobias Markmann <tm@ayena.de> | 2015-09-03 16:20:31 (GMT) |
commit | be6aa6e81b44be67518731d67bb2b72268d351e8 (patch) | |
tree | eaa06c5bf303e627db91f869adba0611da393255 | |
parent | b6ffd5a332b6b21fdba9937fa3a0274556a09cdf (diff) | |
download | swift-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.h | 38 | ||||
-rw-r--r-- | SwifTools/Notifier/NotificationCenterNotifier.mm | 87 | ||||
-rw-r--r-- | SwifTools/Notifier/NotificationCenterNotifierDelegate.h | 22 | ||||
-rw-r--r-- | SwifTools/Notifier/NotificationCenterNotifierDelegate.mm | 26 | ||||
-rw-r--r-- | SwifTools/Notifier/SConscript | 6 | ||||
-rw-r--r-- | Swift/QtUI/QtSwift.cpp | 4 |
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 |