aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schnelli <jonas.schnelli@include7.ch>2013-05-10 22:20:51 +0200
committerJonas Schnelli <jonas.schnelli@include7.ch>2013-05-24 12:51:46 +0200
commitb4b017059514ed0157877984363ed94f5ab098e9 (patch)
treeb8bd52d5059231402fcd6df591e6169e6571e712
parent5b5d399593adbdf8b9b4fb49ef39d51d4eac03cd (diff)
osx: make use of the 10.8+ user notification center to display growl like notifications
- if 10.8, use user notification center, if <10.8, use growl Signed-off-by: Jonas Schnelli <jonas.schnelli@include7.ch>
-rw-r--r--bitcoin-qt.pro4
-rw-r--r--src/qt/macnotificationhandler.h25
-rw-r--r--src/qt/macnotificationhandler.mm65
-rw-r--r--src/qt/notificator.cpp43
-rw-r--r--src/qt/notificator.h12
5 files changed, 128 insertions, 21 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index a217836df8..f41da53067 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -393,8 +393,8 @@ win32:!contains(MINGW_THREAD_BUGFIX, 0) {
DEFINES += _FILE_OFFSET_BITS=64
}
-macx:HEADERS += src/qt/macdockiconhandler.h
-macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm
+macx:HEADERS += src/qt/macdockiconhandler.h src/qt/macnotificationhandler.h
+macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm src/qt/macnotificationhandler.mm
macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0
macx:ICON = src/qt/res/icons/bitcoin.icns
diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h
new file mode 100644
index 0000000000..cd8064c61c
--- /dev/null
+++ b/src/qt/macnotificationhandler.h
@@ -0,0 +1,25 @@
+#ifndef MACNOTIFICATIONHANDLER_H
+#define MACNOTIFICATIONHANDLER_H
+#include <QObject>
+
+/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl).
+ */
+class MacNotificationHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ /** shows a 10.8+ UserNotification in the UserNotificationCenter
+ */
+ void showNotification(const QString &title, const QString &text);
+
+ /** executes AppleScript */
+ void sendAppleScript(const QString &script);
+
+ /** check if OS can handle UserNotifications */
+ bool hasUserNotificationCenterSupport(void);
+ static MacNotificationHandler *instance();
+};
+
+
+#endif // MACNOTIFICATIONHANDLER_H
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
new file mode 100644
index 0000000000..8bb9b887a1
--- /dev/null
+++ b/src/qt/macnotificationhandler.mm
@@ -0,0 +1,65 @@
+#include "macnotificationhandler.h"
+
+#undef slots
+#include <Cocoa/Cocoa.h>
+
+void MacNotificationHandler::showNotification(const QString &title, const QString &text)
+{
+ // check if users OS has support for NSUserNotification
+ if(this->hasUserNotificationCenterSupport()) {
+ // okay, seems like 10.8+
+ QByteArray utf8 = title.toUtf8();
+ char* cString = (char *)utf8.constData();
+ NSString *titleMac = [[NSString alloc] initWithUTF8String:cString];
+
+ utf8 = text.toUtf8();
+ cString = (char *)utf8.constData();
+ NSString *textMac = [[NSString alloc] initWithUTF8String:cString];
+
+ // do everything weak linked (because we will keep <10.8 compatibility)
+ id userNotification = [[NSClassFromString(@"NSUserNotification") alloc] init];
+ [userNotification performSelector:@selector(setTitle:) withObject:titleMac];
+ [userNotification performSelector:@selector(setInformativeText:) withObject:textMac];
+
+ id notificationCenterInstance = [NSClassFromString(@"NSUserNotificationCenter") performSelector:@selector(defaultUserNotificationCenter)];
+ [notificationCenterInstance performSelector:@selector(deliverNotification:) withObject:userNotification];
+
+ [titleMac release];
+ [textMac release];
+ [userNotification release];
+ }
+}
+
+// sendAppleScript just take a QString and executes it as apple script
+void MacNotificationHandler::sendAppleScript(const QString &script)
+{
+ QByteArray utf8 = script.toUtf8();
+ char* cString = (char *)utf8.constData();
+ NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString];
+
+ NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple];
+ NSDictionary *err = nil;
+ [as executeAndReturnError:&err];
+ [as release];
+ [scriptApple release];
+}
+
+bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
+{
+ Class possibleClass = NSClassFromString(@"NSUserNotificationCenter");
+
+ // check if users OS has support for NSUserNotification
+ if(possibleClass!=nil) {
+ return true;
+ }
+ return false;
+}
+
+
+MacNotificationHandler *MacNotificationHandler::instance()
+{
+ static MacNotificationHandler *s_instance = NULL;
+ if (!s_instance)
+ s_instance = new MacNotificationHandler();
+ return s_instance;
+}
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 397e7aa4a0..7cfaef6079 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -18,7 +18,7 @@
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
-extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret);
+#include "macnotificationhandler.h"
#endif
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
@@ -47,19 +47,25 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon,
}
#endif
#ifdef Q_OS_MAC
- // Check if Growl is installed (based on Qt's tray icon implementation)
- CFURLRef cfurl;
- OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
- if (status != kLSApplicationNotFoundErr) {
- CFBundleRef bundle = CFBundleCreate(0, cfurl);
- if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
- if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
- mode = Growl13;
- else
- mode = Growl12;
+ // check if users OS has support for NSUserNotification
+ if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
+ mode = UserNotificationCenter;
+ }
+ else {
+ // Check if Growl is installed (based on Qt's tray icon implementation)
+ CFURLRef cfurl;
+ OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
+ if (status != kLSApplicationNotFoundErr) {
+ CFBundleRef bundle = CFBundleCreate(0, cfurl);
+ if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
+ if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
+ mode = Growl13;
+ else
+ mode = Growl12;
+ }
+ CFRelease(cfurl);
+ CFRelease(bundle);
}
- CFRelease(cfurl);
- CFRelease(bundle);
}
#endif
}
@@ -269,8 +275,14 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te
quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
quotedText.replace("\\", "\\\\").replace("\"", "\\");
QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
- qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0);
+ MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
+}
+
+void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
+ // icon is not supported by the user notification center yet. OSX will use the app icon.
+ MacNotificationHandler::instance()->showNotification(title, text);
}
+
#endif
void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
@@ -286,6 +298,9 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c
notifySystray(cls, title, text, icon, millisTimeout);
break;
#ifdef Q_OS_MAC
+ case UserNotificationCenter:
+ notifyMacUserNotificationCenter(cls, title, text, icon);
+ break;
case Growl12:
case Growl13:
notifyGrowl(cls, title, text, icon);
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index d20673abb6..d1fe37fea5 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -46,11 +46,12 @@ public slots:
private:
QWidget *parent;
enum Mode {
- None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
- Freedesktop, /**< Use DBus org.freedesktop.Notifications */
- QSystemTray, /**< Use QSystemTray::showMessage */
- Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
- Growl13 /**< Use the Growl 1.3 notification system (Mac only) */
+ None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
+ Freedesktop, /**< Use DBus org.freedesktop.Notifications */
+ QSystemTray, /**< Use QSystemTray::showMessage */
+ Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
+ Growl13, /**< Use the Growl 1.3 notification system (Mac only) */
+ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */
};
QString programName;
Mode mode;
@@ -63,6 +64,7 @@ private:
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
#ifdef Q_OS_MAC
void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon);
+ void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon);
#endif
};