diff options
author | Kevin Smith <git@kismith.co.uk> | 2012-03-14 13:12:24 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2012-03-14 13:24:44 (GMT) |
commit | f90fce80371ac12d97c6adc65a9437e4a3a7b268 (patch) | |
tree | 9e277bc46ae0a0cf3e54aa252d1a5c630e35ec83 | |
parent | 1089374439fa6073800679817198e3c39283113e (diff) | |
download | swift-contrib-f90fce80371ac12d97c6adc65a9437e4a3a7b268.zip swift-contrib-f90fce80371ac12d97c6adc65a9437e4a3a7b268.tar.bz2 |
Dispose of notification callbacks once the account signs out.
Fixes segfaults caused by clicking notifications after
the handlers had been freed.
Does not fix GrowlNotifier, which needs fixing later.
-rw-r--r-- | SwifTools/Notifier/GrowlNotifier.h | 3 | ||||
-rw-r--r-- | SwifTools/Notifier/LoggingNotifier.h | 2 | ||||
-rw-r--r-- | SwifTools/Notifier/Notifier.h | 3 | ||||
-rw-r--r-- | SwifTools/Notifier/NullNotifier.h | 1 | ||||
-rw-r--r-- | SwifTools/Notifier/SnarlNotifier.h | 4 | ||||
-rw-r--r-- | SwifTools/Notifier/TogglableNotifier.h | 4 | ||||
-rw-r--r-- | Swift/Controllers/EventNotifier.cpp | 1 | ||||
-rw-r--r-- | Swift/QtUI/WindowsNotifier.cpp | 4 | ||||
-rw-r--r-- | Swift/QtUI/WindowsNotifier.h | 3 |
9 files changed, 24 insertions, 1 deletions
diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h index f4e6803..f1fb8c6 100644 --- a/SwifTools/Notifier/GrowlNotifier.h +++ b/SwifTools/Notifier/GrowlNotifier.h @@ -1,36 +1,39 @@ /* * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <boost/filesystem/fstream.hpp> #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. */ class GrowlNotifier : public Notifier { public: GrowlNotifier(const std::string& name); ~GrowlNotifier(); virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback); virtual bool isExternallyConfigured() const; // Called by the delegate. Don't call. void handleNotificationClicked(void* data); void handleNotificationTimedOut(void* data); + virtual void purgeCallbacks() { +#warning FIXME: Implement + } private: class Private; boost::shared_ptr<Private> p; }; } diff --git a/SwifTools/Notifier/LoggingNotifier.h b/SwifTools/Notifier/LoggingNotifier.h index 32e0610..3d62593 100644 --- a/SwifTools/Notifier/LoggingNotifier.h +++ b/SwifTools/Notifier/LoggingNotifier.h @@ -1,30 +1,32 @@ /* * 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> #include <Swiften/Base/ByteArray.h> namespace Swift { class LoggingNotifier : public Notifier { public: virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback) { notifications.push_back(Notification(type, subject, description, picture, callback)); } struct Notification { Notification(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback) : type(type), subject(subject), description(description), picture(picture), callback(callback) {} Type type; std::string subject; std::string description; boost::filesystem::path picture; boost::function<void()> callback; }; + virtual void purgeCallbacks() {} + std::vector<Notification> notifications; }; } diff --git a/SwifTools/Notifier/Notifier.h b/SwifTools/Notifier/Notifier.h index 1bcd58d..9537ec1 100644 --- a/SwifTools/Notifier/Notifier.h +++ b/SwifTools/Notifier/Notifier.h @@ -4,44 +4,47 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <boost/function.hpp> #include <boost/filesystem/path.hpp> #include <string> #include <vector> namespace Swift { class Notifier { public: virtual ~Notifier(); enum Type { ContactAvailable, ContactUnavailable, ContactStatusChange, IncomingMessage, SystemMessage }; /** * Picture is a PNG image. */ virtual void showMessage( Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback) = 0; virtual bool isAvailable() const { return true; } virtual bool isExternallyConfigured() const { return false; } + /** Remove any pending callbacks. */ + virtual void purgeCallbacks() = 0; + protected: std::string typeToString(Type type); static std::vector<Type> getAllTypes(); static std::vector<Type> getDefaultTypes(); static const int DEFAULT_STATUS_NOTIFICATION_TIMEOUT_SECONDS; static const int DEFAULT_MESSAGE_NOTIFICATION_TIMEOUT_SECONDS; }; } diff --git a/SwifTools/Notifier/NullNotifier.h b/SwifTools/Notifier/NullNotifier.h index 2fa9c11..576dd85 100644 --- a/SwifTools/Notifier/NullNotifier.h +++ b/SwifTools/Notifier/NullNotifier.h @@ -1,17 +1,18 @@ /* * 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 std::string&, const std::string&, const boost::filesystem::path&, boost::function<void()>) { } + virtual void purgeCallbacks() { }; } diff --git a/SwifTools/Notifier/SnarlNotifier.h b/SwifTools/Notifier/SnarlNotifier.h index c96dfa6..eb0eb5a 100644 --- a/SwifTools/Notifier/SnarlNotifier.h +++ b/SwifTools/Notifier/SnarlNotifier.h @@ -1,35 +1,39 @@ /* * 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 <map> #include <SwifTools/Notifier/Notifier.h> #include <SnarlInterface.h> namespace Swift { class Win32NotifierWindow; class SnarlNotifier : public Notifier { public: SnarlNotifier(const std::string& name, Win32NotifierWindow* window, const boost::filesystem::path& icon); ~SnarlNotifier(); virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback); virtual bool isAvailable() const; + virtual void purgeCallbacks() { + notifications.clear(); + } + private: void handleMessageReceived(MSG* message); private: Snarl::V41::SnarlInterface snarl; Win32NotifierWindow* window; bool available; typedef std::map<int, boost::function<void()> > NotificationsMap; NotificationsMap notifications; }; } diff --git a/SwifTools/Notifier/TogglableNotifier.h b/SwifTools/Notifier/TogglableNotifier.h index 7abfd42..a4f0bb6 100644 --- a/SwifTools/Notifier/TogglableNotifier.h +++ b/SwifTools/Notifier/TogglableNotifier.h @@ -18,41 +18,45 @@ namespace Swift { * Set a long-term (usually user-set) enabled. * This may be temporarily overriden by the application, e.g. if the * user is marked DND. */ void setPersistentEnabled(bool b) { persistentEnabled = b; } /** * Set a temporary override to stop notifications without changing the * long-term state. e.g. if the user goes DND, but the persistent * enabled shouldn't be lost when they become available again. */ void setTemporarilyDisabled(bool b) { temporarilyDisabled = b; } /** * Get the result of applying the temporary override to the persistent * enabledness. */ bool getCurrentlyEnabled() const { return persistentEnabled && !temporarilyDisabled; } virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback) { if (getCurrentlyEnabled() || notifier->isExternallyConfigured()) { notifier->showMessage(type, subject, description, picture, callback); } } virtual bool isExternallyConfigured() const { return notifier->isExternallyConfigured(); } + virtual void purgeCallbacks() { + notifier->purgeCallbacks(); + } + private: Notifier* notifier; bool persistentEnabled; bool temporarilyDisabled; }; } diff --git a/Swift/Controllers/EventNotifier.cpp b/Swift/Controllers/EventNotifier.cpp index 7ecc27c..e643ab3 100644 --- a/Swift/Controllers/EventNotifier.cpp +++ b/Swift/Controllers/EventNotifier.cpp @@ -1,64 +1,65 @@ /* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swift/Controllers/EventNotifier.h" #include <boost/bind.hpp> #include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> #include "Swift/Controllers/XMPPEvents/EventController.h" #include "SwifTools/Notifier/Notifier.h" #include "Swiften/Avatars/AvatarManager.h" #include "Swiften/Client/NickResolver.h" #include "Swiften/JID/JID.h" #include "Swift/Controllers/XMPPEvents/MessageEvent.h" #include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h" #include "Swift/Controllers/XMPPEvents/ErrorEvent.h" #include "Swift/Controllers/Settings/SettingsProvider.h" namespace Swift { EventNotifier::EventNotifier(EventController* eventController, Notifier* notifier, AvatarManager* avatarManager, NickResolver* nickResolver) : eventController(eventController), notifier(notifier), avatarManager(avatarManager), nickResolver(nickResolver) { eventController->onEventQueueEventAdded.connect(boost::bind(&EventNotifier::handleEventAdded, this, _1)); } EventNotifier::~EventNotifier() { + notifier->purgeCallbacks(); eventController->onEventQueueEventAdded.disconnect(boost::bind(&EventNotifier::handleEventAdded, this, _1)); } void EventNotifier::handleEventAdded(boost::shared_ptr<StanzaEvent> event) { if (event->getConcluded()) { return; } if (boost::shared_ptr<MessageEvent> messageEvent = boost::dynamic_pointer_cast<MessageEvent>(event)) { JID jid = messageEvent->getStanza()->getFrom(); std::string title = nickResolver->jidToNick(jid); if (!messageEvent->getStanza()->isError() && !messageEvent->getStanza()->getBody().empty()) { JID activationJID = jid; if (messageEvent->getStanza()->getType() == Message::Groupchat) { activationJID = jid.toBare(); } notifier->showMessage(Notifier::IncomingMessage, title, messageEvent->getStanza()->getBody(), avatarManager->getAvatarPath(jid), boost::bind(&EventNotifier::handleNotificationActivated, this, activationJID)); } } else if(boost::shared_ptr<SubscriptionRequestEvent> subscriptionEvent = boost::dynamic_pointer_cast<SubscriptionRequestEvent>(event)) { JID jid = subscriptionEvent->getJID(); std::string title = jid; std::string message = str(format(QT_TRANSLATE_NOOP("", "%1% wants to add you to his/her contact list")) % nickResolver->jidToNick(jid)); notifier->showMessage(Notifier::SystemMessage, title, message, boost::filesystem::path(), boost::function<void()>()); } else if(boost::shared_ptr<ErrorEvent> errorEvent = boost::dynamic_pointer_cast<ErrorEvent>(event)) { notifier->showMessage(Notifier::SystemMessage, QT_TRANSLATE_NOOP("", "Error"), errorEvent->getText(), boost::filesystem::path(), boost::function<void()>()); } } void EventNotifier::handleNotificationActivated(JID jid) { onNotificationActivated(jid); } } diff --git a/Swift/QtUI/WindowsNotifier.cpp b/Swift/QtUI/WindowsNotifier.cpp index 1789451..212f0ca 100644 --- a/Swift/QtUI/WindowsNotifier.cpp +++ b/Swift/QtUI/WindowsNotifier.cpp @@ -15,36 +15,40 @@ #include "QtSwiftUtil.h" namespace Swift { WindowsNotifier::WindowsNotifier(const std::string& name, const boost::filesystem::path& icon, QSystemTrayIcon* tray) : tray(tray) { notifierWindow = new QtWin32NotifierWindow(); snarlNotifier = new SnarlNotifier(name, notifierWindow, icon); connect(tray, SIGNAL(messageClicked()), SLOT(handleMessageClicked())); } WindowsNotifier::~WindowsNotifier() { delete snarlNotifier; delete notifierWindow; } void WindowsNotifier::showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback) { if (snarlNotifier->isAvailable()) { snarlNotifier->showMessage(type, subject, description, picture, callback); return; } std::vector<Notifier::Type> defaultTypes = getDefaultTypes(); if (std::find(defaultTypes.begin(), defaultTypes.end(), type) == defaultTypes.end()) { return; } lastCallback = callback; int timeout = (type == IncomingMessage || type == SystemMessage) ? DEFAULT_MESSAGE_NOTIFICATION_TIMEOUT_SECONDS : DEFAULT_STATUS_NOTIFICATION_TIMEOUT_SECONDS; tray->showMessage(P2QSTRING(subject), P2QSTRING(description), type == SystemMessage ? QSystemTrayIcon::Information : QSystemTrayIcon::NoIcon, timeout * 1000); } void WindowsNotifier::handleMessageClicked() { if (lastCallback) { lastCallback(); } } +void WindowsNotifier::purgeCallbacks() { + lastCallback = boost::function<void()>(); +} + } diff --git a/Swift/QtUI/WindowsNotifier.h b/Swift/QtUI/WindowsNotifier.h index 062b76f..b2b5577 100644 --- a/Swift/QtUI/WindowsNotifier.h +++ b/Swift/QtUI/WindowsNotifier.h @@ -1,36 +1,37 @@ /* * 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 <map> #include <QObject> #include <SwifTools/Notifier/Notifier.h> #include <SwifTools/Notifier/SnarlNotifier.h> class QSystemTrayIcon; namespace Swift { class WindowsNotifier : public QObject, public Notifier { Q_OBJECT public: WindowsNotifier(const std::string& name, const boost::filesystem::path& icon, QSystemTrayIcon* tray); ~WindowsNotifier(); virtual void showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picture, boost::function<void()> callback); - + virtual void purgeCallbacks(); + private slots: void handleMessageClicked(); private: QSystemTrayIcon* tray; Win32NotifierWindow* notifierWindow; SnarlNotifier* snarlNotifier; boost::function<void()> lastCallback; }; } |