LIBS += -lrt
}
-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
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
+ dockIconHandler->setMainWindow((QMainWindow *)this);
trayIconMenu = dockIconHandler->dockMenu();
#endif
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
#endif
-
- notificator = new Notificator(qApp->applicationName(), trayIcon);
}
#ifndef Q_OS_MAC
-#ifndef MACDOCKICONHANDLER_H
-#define MACDOCKICONHANDLER_H
+// Copyright (c) 2011-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <QtCore/QObject>
+#ifndef BITCOIN_QT_MACDOCKICONHANDLER_H
+#define BITCOIN_QT_MACDOCKICONHANDLER_H
+#include <QMainWindow>
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QIcon;
class QMenu;
class QIcon;
class QWidget;
+QT_END_NAMESPACE
#ifdef __OBJC__
@class DockIconClickEventHandler;
class MacDockIconHandler : public QObject
{
Q_OBJECT
+
public:
~MacDockIconHandler();
QMenu *dockMenu();
void setIcon(const QIcon &icon);
-
+ void setMainWindow(QMainWindow *window);
static MacDockIconHandler *instance();
void handleDockIconClickEvent();
DockIconClickEventHandler *m_dockIconClickEventHandler;
QWidget *m_dummyWidget;
QMenu *m_dockMenu;
+ QMainWindow *mainWindow;
};
-#endif // MACDOCKICONCLICKHANDLER_H
+#endif // BITCOIN_QT_MACDOCKICONHANDLER_H
+// Copyright (c) 2011-2013 The Bitcoin Core developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "macdockiconhandler.h"
+#include <QImageWriter>
#include <QMenu>
+#include <QBuffer>
#include <QWidget>
extern void qt_mac_set_dock_menu(QMenu*);
#undef slots
#include <Cocoa/Cocoa.h>
+#if QT_VERSION < 0x050000
+extern void qt_mac_set_dock_menu(QMenu *);
+#endif
+
@interface DockIconClickEventHandler : NSObject
{
MacDockIconHandler* dockIconHandler;
Q_UNUSED(event)
Q_UNUSED(replyEvent)
- if (dockIconHandler)
+ if (dockIconHandler) {
dockIconHandler->handleDockIconClickEvent();
+ }
}
@end
MacDockIconHandler::MacDockIconHandler() : QObject()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this];
+ this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this];
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
+ this->setMainWindow(NULL);
+#if QT_VERSION < 0x050000
qt_mac_set_dock_menu(this->m_dockMenu);
+#elif QT_VERSION >= 0x050200
+ this->m_dockMenu->setAsDockMenu();
+#endif
[pool release];
}
+void MacDockIconHandler::setMainWindow(QMainWindow *window) {
+ this->mainWindow = window;
+}
+
MacDockIconHandler::~MacDockIconHandler()
{
[this->m_dockIconClickEventHandler release];
delete this->m_dummyWidget;
+ this->setMainWindow(NULL);
}
QMenu *MacDockIconHandler::dockMenu()
void MacDockIconHandler::setIcon(const QIcon &icon)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSImage *image;
+ NSImage *image = nil;
if (icon.isNull())
image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
else {
+ // generate NSImage from QIcon and use this as dock icon.
QSize size = icon.actualSize(QSize(128, 128));
QPixmap pixmap = icon.pixmap(size);
- CGImageRef cgImage = pixmap.toMacCGImageRef();
- image = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];
- CFRelease(cgImage);
+
+ // Write image into a R/W buffer from raw pixmap, then save the image.
+ QBuffer notificationBuffer;
+ if (!pixmap.isNull() && notificationBuffer.open(QIODevice::ReadWrite)) {
+ QImageWriter writer(¬ificationBuffer, "PNG");
+ if (writer.write(pixmap.toImage())) {
+ NSData* macImgData = [NSData dataWithBytes:notificationBuffer.buffer().data()
+ length:notificationBuffer.buffer().size()];
+ image = [[NSImage alloc] initWithData:macImgData];
+ }
+ }
+
+ if(!image) {
+ // if testnet image could not be created, load std. app icon
+ image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
+ }
}
[NSApp setApplicationIconImage:image];
void MacDockIconHandler::handleDockIconClickEvent()
{
+ if (this->mainWindow)
+ {
+ this->mainWindow->activateWindow();
+ this->mainWindow->show();
+ }
+
emit this->dockIconClicked();
}
--- /dev/null
+// Copyright (c) 2011-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_MACNOTIFICATIONHANDLER_H
+#define BITCOIN_QT_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 // BITCOIN_QT_MACNOTIFICATIONHANDLER_H
--- /dev/null
+// Copyright (c) 2011-2013 The Bitcoin Core developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "macnotificationhandler.h"
+
+#undef slots
+#import <objc/runtime.h>
+#include <Cocoa/Cocoa.h>
+
+// Add an obj-c category (extension) to return the expected bundle identifier
+@implementation NSBundle(returnCorrectIdentifier)
+- (NSString *)__bundleIdentifier
+{
+ if (self == [NSBundle mainBundle]) {
+ return @"org.bitcoinfoundation.Bitcoin-Qt";
+ } else {
+ return [self __bundleIdentifier];
+ }
+}
+@end
+
+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();
+
+ Class aPossibleClass = objc_getClass("NSBundle");
+ if (aPossibleClass) {
+ // change NSBundle -bundleIdentifier method to return a correct bundle identifier
+ // a bundle identifier is required to use OSXs User Notification Center
+ method_exchangeImplementations(class_getInstanceMethod(aPossibleClass, @selector(bundleIdentifier)),
+ class_getInstanceMethod(aPossibleClass, @selector(__bundleIdentifier)));
+ }
+ }
+ return s_instance;
+}
+// Copyright (c) 2011-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "notificator.h"
-#include <QMetaType>
-#include <QVariant>
-#include <QIcon>
#include <QApplication>
-#include <QStyle>
#include <QByteArray>
-#include <QSystemTrayIcon>
+#include <QIcon>
+#include <QImageWriter>
#include <QMessageBox>
+#include <QMetaType>
+#include <QStyle>
+#include <QSystemTrayIcon>
#include <QTemporaryFile>
-#include <QImageWriter>
-
+#include <QVariant>
#ifdef USE_DBUS
-#include <QtDBus/QtDBus>
#include <stdint.h>
+#include <QtDBus>
#endif
-
+// Include ApplicationServices.h after QtDbus to avoid redefinition of check().
+// This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details.
+// Note: This could also be worked around using:
+// #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
-extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret);
+#include "macnotificationhandler.h"
#endif
+
+#ifdef USE_DBUS
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
+#endif
-Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent):
+Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
QObject(parent),
parent(parent),
programName(programName),
}
#ifdef USE_DBUS
interface = new QDBusInterface("org.freedesktop.Notifications",
- "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
+ "/org/freedesktop/Notifications", "org.freedesktop.Notifications");
if(interface->isValid())
{
mode = Freedesktop;
}
#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
}
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)
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);
-#ifndef NOTIFICATOR_H
-#define NOTIFICATOR_H
+// Copyright (c) 2011-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_NOTIFICATOR_H
+#define BITCOIN_QT_NOTIFICATOR_H
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
-#include <QObject>
#include <QIcon>
+#include <QObject>
QT_BEGIN_NAMESPACE
class QSystemTrayIcon;
+
#ifdef USE_DBUS
class QDBusInterface;
#endif
class Notificator: public QObject
{
Q_OBJECT
+
public:
/** Create a new notificator.
@note Ownership of trayIcon is not transferred to this object.
*/
- Notificator(const QString &programName=QString(), QSystemTrayIcon *trayIcon=0, QWidget *parent=0);
+ Notificator(const QString &programName, QSystemTrayIcon *trayIcon, QWidget *parent);
~Notificator();
// Message class
enum Class
{
- Information, /**< Informational message */
- Warning, /**< Notify user of potential problem */
- Critical /**< An error occurred */
+ Information, /**< Informational message */
+ Warning, /**< Notify user of potential problem */
+ Critical /**< An error occurred */
};
public slots:
-
/** Show notification message.
@param[in] cls general message class
@param[in] title title shown with message
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;
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
};
-#endif // NOTIFICATOR_H
+#endif // BITCOIN_QT_NOTIFICATOR_H