Browse Source

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>
miguelfreitas
Jonas Schnelli 12 years ago
parent
commit
b4b0170595
  1. 4
      bitcoin-qt.pro
  2. 25
      src/qt/macnotificationhandler.h
  3. 65
      src/qt/macnotificationhandler.mm
  4. 43
      src/qt/notificator.cpp
  5. 12
      src/qt/notificator.h

4
bitcoin-qt.pro

@ -393,8 +393,8 @@ win32:!contains(MINGW_THREAD_BUGFIX, 0) {
DEFINES += _FILE_OFFSET_BITS=64 DEFINES += _FILE_OFFSET_BITS=64
} }
macx:HEADERS += src/qt/macdockiconhandler.h macx:HEADERS += src/qt/macdockiconhandler.h src/qt/macnotificationhandler.h
macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm src/qt/macnotificationhandler.mm
macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0
macx:ICON = src/qt/res/icons/bitcoin.icns macx:ICON = src/qt/res/icons/bitcoin.icns

25
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

65
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;
}

43
src/qt/notificator.cpp

@ -18,7 +18,7 @@
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); #include "macnotificationhandler.h"
#endif #endif
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128 // https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
@ -47,19 +47,25 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon,
} }
#endif #endif
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
// Check if Growl is installed (based on Qt's tray icon implementation) // check if users OS has support for NSUserNotification
CFURLRef cfurl; if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); mode = UserNotificationCenter;
if (status != kLSApplicationNotFoundErr) { }
CFBundleRef bundle = CFBundleCreate(0, cfurl); else {
if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { // Check if Growl is installed (based on Qt's tray icon implementation)
if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) CFURLRef cfurl;
mode = Growl13; OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
else if (status != kLSApplicationNotFoundErr) {
mode = Growl12; 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 #endif
} }
@ -269,8 +275,14 @@ void Notificator::notifyGrowl(Class cls, const QString &title, const QString &te
quotedTitle.replace("\\", "\\\\").replace("\"", "\\"); quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
quotedText.replace("\\", "\\\\").replace("\"", "\\"); quotedText.replace("\\", "\\\\").replace("\"", "\\");
QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp"); 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 #endif
void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) 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); notifySystray(cls, title, text, icon, millisTimeout);
break; break;
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
case UserNotificationCenter:
notifyMacUserNotificationCenter(cls, title, text, icon);
break;
case Growl12: case Growl12:
case Growl13: case Growl13:
notifyGrowl(cls, title, text, icon); notifyGrowl(cls, title, text, icon);

12
src/qt/notificator.h

@ -46,11 +46,12 @@ public slots:
private: private:
QWidget *parent; QWidget *parent;
enum Mode { enum Mode {
None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
Freedesktop, /**< Use DBus org.freedesktop.Notifications */ Freedesktop, /**< Use DBus org.freedesktop.Notifications */
QSystemTray, /**< Use QSystemTray::showMessage */ QSystemTray, /**< Use QSystemTray::showMessage */
Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
Growl13 /**< Use the Growl 1.3 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; QString programName;
Mode mode; Mode mode;
@ -63,6 +64,7 @@ private:
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon); 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 #endif
}; };

Loading…
Cancel
Save