Fix make problem OS X 61/head
authorgades <dmitriy@korniychuk.org.ua>
Sat, 22 Nov 2014 09:09:41 +0000 (11:09 +0200)
committergades <dmitriy@korniychuk.org.ua>
Sat, 22 Nov 2014 09:09:41 +0000 (11:09 +0200)
novacoin-qt.pro
src/qt/bitcoingui.cpp
src/qt/macdockiconhandler.h
src/qt/macdockiconhandler.mm
src/qt/macnotificationhandler.h [new file with mode: 0644]
src/qt/macnotificationhandler.mm [new file with mode: 0644]
src/qt/notificator.cpp
src/qt/notificator.h

index 2552e53..feef761 100644 (file)
@@ -426,8 +426,10 @@ windows:!contains(MINGW_THREAD_BUGFIX, 0) {
     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
index 5db27fe..4b7368a 100644 (file)
@@ -475,6 +475,7 @@ void BitcoinGUI::createTrayIcon()
 #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
 
@@ -493,8 +494,6 @@ void BitcoinGUI::createTrayIcon()
     trayIconMenu->addSeparator();
     trayIconMenu->addAction(quitAction);
 #endif
-
-    notificator = new Notificator(qApp->applicationName(), trayIcon);
 }
 
 #ifndef Q_OS_MAC
index 2092fb2..8cf6576 100644 (file)
@@ -1,11 +1,19 @@
-#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;
@@ -18,12 +26,13 @@ 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();
@@ -39,6 +48,7 @@ private:
     DockIconClickEventHandler *m_dockIconClickEventHandler;
     QWidget *m_dummyWidget;
     QMenu *m_dockMenu;
+    QMainWindow *mainWindow;
 };
 
-#endif // MACDOCKICONCLICKHANDLER_H
+#endif // BITCOIN_QT_MACDOCKICONHANDLER_H
index 7568440..3270113 100644 (file)
@@ -1,7 +1,12 @@
+// 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*);
@@ -9,6 +14,10 @@ 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;
@@ -38,8 +47,9 @@ extern void qt_mac_set_dock_menu(QMenu*);
     Q_UNUSED(event)
     Q_UNUSED(replyEvent)
 
-    if (dockIconHandler)
+    if (dockIconHandler) {
         dockIconHandler->handleDockIconClickEvent();
+    }
 }
 
 @end
@@ -47,18 +57,28 @@ extern void qt_mac_set_dock_menu(QMenu*);
 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()
@@ -69,15 +89,29 @@ 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(&notificationBuffer, "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];
@@ -95,5 +129,11 @@ MacDockIconHandler *MacDockIconHandler::instance()
 
 void MacDockIconHandler::handleDockIconClickEvent()
 {
+    if (this->mainWindow)
+    {
+        this->mainWindow->activateWindow();
+        this->mainWindow->show();
+    }
+
     emit this->dockIconClicked();
 }
diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h
new file mode 100644 (file)
index 0000000..f7a4cb7
--- /dev/null
@@ -0,0 +1,30 @@
+// 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
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
new file mode 100644 (file)
index 0000000..aa50a0d
--- /dev/null
@@ -0,0 +1,91 @@
+// 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;
+}
index 628dca1..3d588cd 100644 (file)
@@ -1,30 +1,39 @@
+// 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),
@@ -40,26 +49,32 @@ Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon,
     }
 #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
 }
@@ -269,8 +284,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 +307,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);
index abb4710..61c27e7 100644 (file)
@@ -1,11 +1,20 @@
-#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
@@ -15,23 +24,23 @@ QT_END_NAMESPACE
 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
@@ -46,11 +55,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,7 +73,8 @@ 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
 };
 
-#endif // NOTIFICATOR_H
+#endif // BITCOIN_QT_NOTIFICATOR_H