From 3ae8cccfe9c6bfed5dda5f024a5cb046ccfc9793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be> Date: Sun, 12 Sep 2010 18:21:36 +0200 Subject: Move Notifier to SwifTools diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct index a67817a..5a8791b 100644 --- a/BuildTools/SCons/SConstruct +++ b/BuildTools/SCons/SConstruct @@ -363,6 +363,22 @@ if env["PLATFORM"] == "darwin" : env["SPARKLE_FRAMEWORK"] = "/Library/Frameworks/Sparkle.framework" conf.Finish() +# Growl +env["HAVE_GROWL"] = 0 +if env["PLATFORM"] == "darwin" : + growl_flags = { + "FRAMEWORKPATH": ["/Library/Frameworks"], + "FRAMEWORKS": ["Growl"] + } + growl_env = conf_env.Clone() + growl_env.MergeFlags(growl_flags) + conf = Configure(growl_env, custom_tests = { "CheckObjCHeader" : checkObjCHeader }) + if conf.CheckObjCHeader("Growl/Growl.h") : + env["HAVE_GROWL"] = 1 + env["GROWL_FLAGS"] = growl_flags + env["GROWL_FRAMEWORK"] = "/Library/Frameworks/Growl.framework" + conf.Finish() + # LibXML conf = Configure(conf_env) if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") : diff --git a/SwifTools/Notifier/GrowlNotifier.cpp b/SwifTools/Notifier/GrowlNotifier.cpp new file mode 100644 index 0000000..4c671ac --- /dev/null +++ b/SwifTools/Notifier/GrowlNotifier.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +// FIXME: Is it safe to pass boost::function<void()> by raw values? +// FIXME: Should we release the strings created in the constructor? + +#include <cassert> + +#include "Swiften/Base/ByteArray.h" +#include "SwifTools/Notifier/GrowlNotifier.h" + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +namespace { + struct Context { + Context() {} + Context(const boost::function<void()>& callback) : callback(callback) {} + + boost::function<void()> callback; + }; + + void notificationClicked(CFPropertyListRef growlContext) { + Context context; + + CFDataRef growlContextData = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) growlContext, 0); + assert(CFDataGetLength(growlContextData) == sizeof(Context)); + CFDataGetBytes(growlContextData, CFRangeMake(0, CFDataGetLength(growlContextData)), (UInt8*) &context); + + context.callback(); + } + + void notificationTimedout(CFPropertyListRef) { + } +} + +namespace Swift { + +GrowlNotifier::GrowlNotifier(const String& name) { + // All notifications + CFMutableArrayRef allNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactAvailable))); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactUnavailable))); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactStatusChange))); + CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(IncomingMessage))); + + // Default Notifications + CFMutableArrayRef defaultNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactAvailable))); + CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(IncomingMessage))); + + // Initialize delegate + InitGrowlDelegate(&delegate_); + delegate_.applicationName = SWIFTEN_STRING_TO_CFSTRING(name); + CFTypeRef keys[] = { GROWL_NOTIFICATIONS_ALL, GROWL_NOTIFICATIONS_DEFAULT }; + CFTypeRef values[] = { allNotifications, defaultNotifications }; + delegate_.registrationDictionary = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + delegate_.growlNotificationWasClicked = ¬ificationClicked; + delegate_.growlNotificationTimedOut = ¬ificationTimedout; + Growl_SetDelegate(&delegate_); +} + +void GrowlNotifier::showMessage(Type type, const String& subject, const String& description, const ByteArray& picture, boost::function<void()> callback) { + CFStringRef cfSubject = SWIFTEN_STRING_TO_CFSTRING(subject); + CFStringRef cfDescription = SWIFTEN_STRING_TO_CFSTRING(description); + CFStringRef cfName = SWIFTEN_STRING_TO_CFSTRING(typeToString(type)); + CFDataRef cfIcon = CFDataCreate( NULL, (UInt8*) picture.getData(), picture.getSize()); + + Context context(callback); + CFDataRef cfContextData[1]; + cfContextData[0] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &context, sizeof(Context)); + CFArrayRef cfContext = CFArrayCreate( kCFAllocatorDefault, (const void **) cfContextData, 1, &kCFTypeArrayCallBacks ); + CFRelease(cfContextData[0]); + + Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext(cfSubject, cfDescription, cfName, cfIcon, 0, false, cfContext); + + CFRelease(cfContext); + CFRelease(cfIcon); + CFRelease(cfName); + CFRelease(cfDescription); + CFRelease(cfSubject); +} + +String GrowlNotifier::typeToString(Type type) { + switch (type) { + case ContactAvailable: return "Contact Becomes Available"; + case ContactUnavailable: return "Contact Becomes Unavailable"; + case ContactStatusChange: return "Contact Changes Status"; + case IncomingMessage: return "Incoming Message"; + } + assert(false); + return ""; +} + +} diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h new file mode 100644 index 0000000..fab3b5e --- /dev/null +++ b/SwifTools/Notifier/GrowlNotifier.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <CoreFoundation/CoreFoundation.h> +#include <Growl/Growl.h> + +#include "SwifTools/Notifier/Notifier.h" + +namespace Swift { + /** + * Preconditions for using growlnotifier: + * - Must be part a bundle. + * - The Carbon/Cocoa application loop must be running (e.g. through QApplication) + * such that notifications are coming through. + * TODO: Find out what the easiest way is to do this without a QApplication. + */ + class GrowlNotifier : public Notifier { + public: + GrowlNotifier(const String& name); + + virtual void showMessage(Type type, const String& subject, const String& description, const ByteArray& picture, boost::function<void()> callback); + + private: + String typeToString(Type type); + + private: + Growl_Delegate delegate_; + }; +} diff --git a/SwifTools/Notifier/Notifier.cpp b/SwifTools/Notifier/Notifier.cpp new file mode 100644 index 0000000..2c2cfe5 --- /dev/null +++ b/SwifTools/Notifier/Notifier.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "SwifTools/Notifier/Notifier.h" + +namespace Swift { + +Notifier::~Notifier() { +} + +} diff --git a/SwifTools/Notifier/Notifier.h b/SwifTools/Notifier/Notifier.h new file mode 100644 index 0000000..7eb09f4 --- /dev/null +++ b/SwifTools/Notifier/Notifier.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/function.hpp> + +#include "Swiften/Base/String.h" + +namespace Swift { + class Notifier { + public: + virtual ~Notifier(); + + enum Type { ContactAvailable, ContactUnavailable, ContactStatusChange, IncomingMessage }; + + /** + * Picture is a PNG image. + */ + virtual void showMessage( + Type type, + const String& subject, + const String& description, + const ByteArray& picture, + boost::function<void()> callback) = 0; + }; +} diff --git a/SwifTools/Notifier/NullNotifier.h b/SwifTools/Notifier/NullNotifier.h new file mode 100644 index 0000000..d278e4f --- /dev/null +++ b/SwifTools/Notifier/NullNotifier.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "SwifTools/Notifier/Notifier.h" + +namespace Swift { + class NullNotifier : public Notifier { + public: + virtual void showMessage(Type, const String&, const String&, const ByteArray&, boost::function<void()>) { + } + }; +} diff --git a/SwifTools/Notifier/SConscript b/SwifTools/Notifier/SConscript new file mode 100644 index 0000000..89fc31b --- /dev/null +++ b/SwifTools/Notifier/SConscript @@ -0,0 +1,13 @@ +Import("swiftools_env") + +sources = [ + "Notifier.cpp", + ] + +if swiftools_env.get("HAVE_GROWL", False) : + sources += [ + "GrowlNotifier.cpp", + ] + +objects = swiftools_env.StaticObject(sources) +swiftools_env.Append(SWIFTOOLS_OBJECTS = objects) diff --git a/SwifTools/SConscript b/SwifTools/SConscript index 2675b9f..6b9b727 100644 --- a/SwifTools/SConscript +++ b/SwifTools/SConscript @@ -48,6 +48,7 @@ if env["SCONS_STAGE"] == "build" : SConscript(dirs = [ "Dock", + "Notifier", "Idle/IdleQuerierTest", "Idle/UnitTest", "UnitTest" diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index d4222e3..834dacd 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -83,6 +83,7 @@ MainController::MainController( CapsStorage* capsStorage, VCardStorageFactory* vcardStorageFactory, Dock* dock, + Notifier* notifier, bool useDelayForLatency) : timerFactory_(&boostIOServiceThread_.getIOService()), idleDetector_(&idleQuerier_, &timerFactory_, 100), @@ -114,6 +115,7 @@ MainController::MainController( mucSearchWindowFactory_ = mucSearchWindowFactory; eventWindowFactory_ = eventWindowFactory; dock_ = dock; + notifier_ = notifier; chatListWindowFactory_ = chatListWindowFactory; uiEventStream_ = new UIEventStream(); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 7aad4a0..7fbf54f 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -54,6 +54,7 @@ namespace Swift { class SoftwareVersionResponder; class LoginWindowFactory; class MUCController; + class Notifier; class PresenceOracle; class SystemTray; class SystemTrayController; @@ -88,6 +89,7 @@ namespace Swift { CapsStorage* capsStorage, VCardStorageFactory* vcardStorageFactory, Dock* dock, + Notifier* notifier, bool useDelayForLatency); ~MainController(); @@ -134,6 +136,7 @@ namespace Swift { VCardStorageFactory* vcardStorageFactory_; VCardManager* vcardManager_; Dock* dock_; + Notifier* notifier_; ChatController* chatController_; XMPPRosterController* xmppRosterController_; RosterController* rosterController_; diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index 758fe29..ee97fc6 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -36,6 +36,11 @@ #include "Swift/Controllers/BuildVersion.h" #include "SwifTools/AutoUpdater/AutoUpdater.h" #include "SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h" +#if defined(HAVE_GROWL) +#include "SwifTools/Notifier/GrowlNotifier.h" +#else +#include "SwifTools/Notifier/NullNotifier.h" +#endif #if defined(SWIFTEN_PLATFORM_MACOSX) #include "SwifTools/Dock/MacOSXDock.h" #else @@ -90,6 +95,11 @@ QtSwift::QtSwift(po::variables_map options) : autoUpdater_(NULL) { capsStorage_ = new CapsFileStorage(applicationPathProvider_->getDataDir() / "caps"); chatWindowFactory_ = new QtChatWindowFactory(splitter_, settings_, tabs_, ""); soundPlayer_ = new QtSoundPlayer(applicationPathProvider_); +#if defined(HAVE_GROWL) + notifier_ = new GrowlNotifier(SWIFT_APPLICATION_NAME); +#else + notifier_ = new NullNotifier(); +#endif #if defined(SWIFTEN_PLATFORM_MACOSX) dock_ = new MacOSXDock(&cocoaApplication_); @@ -131,6 +141,7 @@ QtSwift::QtSwift(po::variables_map options) : autoUpdater_(NULL) { capsStorage_, vcardStorageFactory_, dock_, + notifier_, options.count("latency-debug") > 0); mainControllers_.push_back(mainController); } diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h index 657b749..abc8c75 100644 --- a/Swift/QtUI/QtSwift.h +++ b/Swift/QtUI/QtSwift.h @@ -27,6 +27,7 @@ class QSplitter; namespace Swift { class Dock; + class Notifier; class VCardStorageFactory; class AutoUpdater; class ApplicationPathProvider; @@ -70,6 +71,7 @@ namespace Swift { CapsStorage* capsStorage_; VCardStorageFactory* vcardStorageFactory_; AutoUpdater* autoUpdater_; + Notifier* notifier_; #if defined(SWIFTEN_PLATFORM_MACOSX) CocoaApplication cocoaApplication_; #endif diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 9f08f4f..bf9e5cf 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -35,6 +35,9 @@ myenv.MergeFlags(env["ZLIB_FLAGS"]) myenv.MergeFlags(env["OPENSSL_FLAGS"]) myenv.MergeFlags(env.get("LIBXML_FLAGS", "")) myenv.MergeFlags(env.get("EXPAT_FLAGS", "")) +if myenv.get("HAVE_GROWL", False) : + myenv.MergeFlags(myenv["GROWL_FLAGS"]) + myenv.Append(CPPDEFINES = ["HAVE_GROWL"]) myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) myenv.Tool("qt4", toolpath = ["#/BuildTools/SCons/Tools"]) diff --git a/Swiften/Notifier/GrowlNotifier.cpp b/Swiften/Notifier/GrowlNotifier.cpp deleted file mode 100644 index 8f92b04..0000000 --- a/Swiften/Notifier/GrowlNotifier.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -// FIXME: Is it safe to pass boost::function<void()> by raw values? -// FIXME: Should we release the strings created in the constructor? - -#include <cassert> - -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Notifier/GrowlNotifier.h" - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -namespace { - struct Context { - Context() {} - Context(const boost::function<void()>& callback) : callback(callback) {} - - boost::function<void()> callback; - }; - - void notificationClicked(CFPropertyListRef growlContext) { - Context context; - - CFDataRef growlContextData = (CFDataRef) CFArrayGetValueAtIndex((CFArrayRef) growlContext, 0); - assert(CFDataGetLength(growlContextData) == sizeof(Context)); - CFDataGetBytes(growlContextData, CFRangeMake(0, CFDataGetLength(growlContextData)), (UInt8*) &context); - - context.callback(); - } - - void notificationTimedout(CFPropertyListRef) { - } -} - -namespace Swift { - -GrowlNotifier::GrowlNotifier(const String& name) { - // All notifications - CFMutableArrayRef allNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactAvailable))); - CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactUnavailable))); - CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactStatusChange))); - CFArrayAppendValue(allNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(IncomingMessage))); - - // Default Notifications - CFMutableArrayRef defaultNotifications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(ContactAvailable))); - CFArrayAppendValue(defaultNotifications, SWIFTEN_STRING_TO_CFSTRING(typeToString(IncomingMessage))); - - // Initialize delegate - InitGrowlDelegate(&delegate_); - delegate_.applicationName = SWIFTEN_STRING_TO_CFSTRING(name); - CFTypeRef keys[] = { GROWL_NOTIFICATIONS_ALL, GROWL_NOTIFICATIONS_DEFAULT }; - CFTypeRef values[] = { allNotifications, defaultNotifications }; - delegate_.registrationDictionary = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - delegate_.growlNotificationWasClicked = ¬ificationClicked; - delegate_.growlNotificationTimedOut = ¬ificationTimedout; - Growl_SetDelegate(&delegate_); -} - -void GrowlNotifier::showMessage(Type type, const String& subject, const String& description, const ByteArray& picture, boost::function<void()> callback) { - CFStringRef cfSubject = SWIFTEN_STRING_TO_CFSTRING(subject); - CFStringRef cfDescription = SWIFTEN_STRING_TO_CFSTRING(description); - CFStringRef cfName = SWIFTEN_STRING_TO_CFSTRING(typeToString(type)); - CFDataRef cfIcon = CFDataCreate( NULL, (UInt8*) picture.getData(), picture.getSize()); - - Context context(callback); - CFDataRef cfContextData[1]; - cfContextData[0] = CFDataCreate(kCFAllocatorDefault, (const UInt8*) &context, sizeof(Context)); - CFArrayRef cfContext = CFArrayCreate( kCFAllocatorDefault, (const void **) cfContextData, 1, &kCFTypeArrayCallBacks ); - CFRelease(cfContextData[0]); - - Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext(cfSubject, cfDescription, cfName, cfIcon, 0, false, cfContext); - - CFRelease(cfContext); - CFRelease(cfIcon); - CFRelease(cfName); - CFRelease(cfDescription); - CFRelease(cfSubject); -} - -String GrowlNotifier::typeToString(Type type) { - switch (type) { - case ContactAvailable: return "Contact Becomes Available"; - case ContactUnavailable: return "Contact Becomes Unavailable"; - case ContactStatusChange: return "Contact Changes Status"; - case IncomingMessage: return "Incoming Message"; - } - assert(false); - return ""; -} - -} diff --git a/Swiften/Notifier/GrowlNotifier.h b/Swiften/Notifier/GrowlNotifier.h deleted file mode 100644 index 5743fe5..0000000 --- a/Swiften/Notifier/GrowlNotifier.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <CoreFoundation/CoreFoundation.h> -#include <Growl/Growl.h> - -#include "Swiften/Notifier/Notifier.h" - -namespace Swift { - /** - * Preconditions for using growlnotifier: - * - Must be part a bundle. - * - The Carbon/Cocoa application loop must be running (e.g. through QApplication) - * such that notifications are coming through. - * TODO: Find out what the easiest way is to do this without a QApplication. - */ - class GrowlNotifier : public Notifier { - public: - GrowlNotifier(const String& name); - - virtual void showMessage(Type type, const String& subject, const String& description, const ByteArray& picture, boost::function<void()> callback); - - private: - String typeToString(Type type); - - private: - Growl_Delegate delegate_; - }; -} diff --git a/Swiften/Notifier/Notifier.cpp b/Swiften/Notifier/Notifier.cpp deleted file mode 100644 index 44e7b32..0000000 --- a/Swiften/Notifier/Notifier.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/Notifier/Notifier.h" - -namespace Swift { - -Notifier::~Notifier() { -} - -} diff --git a/Swiften/Notifier/Notifier.h b/Swiften/Notifier/Notifier.h deleted file mode 100644 index 7eb09f4..0000000 --- a/Swiften/Notifier/Notifier.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <boost/function.hpp> - -#include "Swiften/Base/String.h" - -namespace Swift { - class Notifier { - public: - virtual ~Notifier(); - - enum Type { ContactAvailable, ContactUnavailable, ContactStatusChange, IncomingMessage }; - - /** - * Picture is a PNG image. - */ - virtual void showMessage( - Type type, - const String& subject, - const String& description, - const ByteArray& picture, - boost::function<void()> callback) = 0; - }; -} diff --git a/Swiften/SConscript b/Swiften/SConscript index 7689ffc..11c976e 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -43,7 +43,6 @@ if env["SCONS_STAGE"] == "build" : "MUC/MUCOccupant.cpp", "MUC/MUCRegistry.cpp", "MUC/MUCBookmarkManager.cpp", - "Notifier/Notifier.cpp", "Presence/PresenceOracle.cpp", "Presence/PresenceSender.cpp", "Queries/IQChannel.cpp", @@ -107,7 +106,6 @@ if env["SCONS_STAGE"] == "build" : "StringCodecs/PBKDF2.cpp", "StringCodecs/Hexify.cpp", ] -# "Notifier/GrowlNotifier.cpp", if myenv.get("HAVE_OPENSSL", 0) : sources += ["TLS/OpenSSL/OpenSSLContext.cpp"] -- cgit v0.10.2-6-g49f6