File indexing completed on 2024-04-28 04:44:14
0001 /* 0002 SnoreNotify is a Notification Framework based on Qt 0003 Copyright (C) 2014-2015 Hannah von Reth <vonreth@kde.org> 0004 0005 SnoreNotify is free software: you can redistribute it and/or modify 0006 it under the terms of the GNU Lesser General Public License as published by 0007 the Free Software Foundation, either version 3 of the License, or 0008 (at your option) any later version. 0009 0010 SnoreNotify is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU Lesser General Public License for more details. 0014 0015 You should have received a copy of the GNU Lesser General Public License 0016 along with SnoreNotify. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 #include "snore_p.h" 0020 #include "snore.h" 0021 #include "snoreconstants.h" 0022 #include "plugins/plugins.h" 0023 #include "plugins/snorebackend.h" 0024 #include "plugins/snorefrontend.h" 0025 #include "plugins/plugincontainer.h" 0026 #include "notification/notification_p.h" 0027 #include "version.h" 0028 0029 #include <QGuiApplication> 0030 #include <QSettings> 0031 #include <QTemporaryDir> 0032 0033 using namespace Snore; 0034 0035 #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) 0036 Q_LOGGING_CATEGORY(SNORE, "libsnorenotify", QtWarningMsg) 0037 #else 0038 Q_LOGGING_CATEGORY(SNORE, "libsnorenotify") 0039 #endif 0040 0041 SnoreCorePrivate::SnoreCorePrivate(): 0042 m_localSettingsPrefix(qApp->applicationName().isEmpty() ? QStringLiteral("SnoreNotify") : qApp->applicationName()) 0043 { 0044 if (qEnvironmentVariableIsSet("LIBSNORE_SETTINGS_FILE")) { 0045 m_settings = new QSettings(QString::fromUtf8(qgetenv("LIBSNORE_SETTINGS_FILE")), QSettings::IniFormat); 0046 } else { 0047 m_settings = new QSettings(QStringLiteral("Snorenotify"), QStringLiteral("libsnore"), this); 0048 } 0049 qCDebug(SNORE) << "Version:" << Version::version(); 0050 if (!Version::revision().isEmpty()) { 0051 qCDebug(SNORE) << "Revision:" << Version::revision(); 0052 } 0053 0054 qCDebug(SNORE) << "Temp dir is" << tempPath(); 0055 qCDebug(SNORE) << "Snore settings are located in" << m_settings->fileName(); 0056 qCDebug(SNORE) << "Snore local settings are located in" << normalizeSettingsKey(QStringLiteral("Test"), LocalSetting); 0057 0058 connect(qApp, &QCoreApplication::aboutToQuit, this, &SnoreCorePrivate::slotAboutToQuit); 0059 } 0060 0061 SnoreCorePrivate::~SnoreCorePrivate() 0062 { 0063 0064 } 0065 0066 Application SnoreCorePrivate::defaultApplication() 0067 { 0068 if (!SnoreCore::instance().aplications().contains(m_defaultApp.key())) { 0069 SnoreCore::instance().registerApplication(m_defaultApp); 0070 } 0071 return m_defaultApp; 0072 } 0073 0074 void SnoreCorePrivate::slotNotificationActionInvoked(Notification notification) 0075 { 0076 Q_Q(SnoreCore); 0077 emit q->actionInvoked(notification); 0078 } 0079 0080 void SnoreCorePrivate::slotNotificationDisplayed(Notification notification) 0081 { 0082 emit notificationDisplayed(notification); 0083 startNotificationTimeoutTimer(notification); 0084 } 0085 0086 bool SnoreCorePrivate::setBackendIfAvailible(const QString &backend) 0087 { 0088 Q_Q(SnoreCore); 0089 if (m_pluginNames[SnorePlugin::Backend].contains(backend)) { 0090 if (backend == q->primaryNotificationBackend()) { 0091 return true; 0092 } 0093 const QHash<QString, PluginContainer *> backends = PluginContainer::pluginCache(SnorePlugin::Backend); 0094 if (!backends.contains(backend)) { 0095 qCDebug(SNORE) << "Unknown Backend:" << backend; 0096 return false; 0097 } 0098 qCDebug(SNORE) << "Setting Notification Backend to:" << backend; 0099 SnoreBackend *b = qobject_cast<SnoreBackend *>(backends.value(backend)->load()); 0100 if (!b->isReady()) { 0101 qCDebug(SNORE) << "Backend not ready:" << b->errorString(); 0102 0103 emit q->primaryNotificationBackendError(b->errorString()); 0104 return false; 0105 } 0106 if (m_notificationBackend) { 0107 m_notificationBackend->disable(); 0108 } 0109 m_notificationBackend = b; 0110 m_notificationBackend->enable(); 0111 q->setSettingsValue(Constants::SettingsKeys::PrimaryBackend, backend); 0112 0113 connect(b, &SnoreBackend::error, [this, b](const QString &) { 0114 slotInitPrimaryNotificationBackend(); 0115 }); 0116 emit q->primaryNotificationBackendChanged(b->name()); 0117 return true; 0118 } 0119 return false; 0120 } 0121 0122 bool SnoreCorePrivate::slotInitPrimaryNotificationBackend() 0123 { 0124 Q_Q(SnoreCore); 0125 qCDebug(SNORE) << q->settingsValue(Constants::SettingsKeys::PrimaryBackend).toString(); 0126 if (setBackendIfAvailible(q->settingsValue(Constants::SettingsKeys::PrimaryBackend).toString())) { 0127 return true; 0128 } 0129 #ifdef Q_OS_WIN 0130 if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 && setBackendIfAvailible(QLatin1String("Windows Toast"))) { 0131 return true; 0132 } 0133 if (setBackendIfAvailible(QStringLiteral("Growl"))) { 0134 return true; 0135 } 0136 if (setBackendIfAvailible(QStringLiteral("Snarl"))) { 0137 return true; 0138 } 0139 #elif defined(Q_OS_LINUX) 0140 if (setBackendIfAvailible(QStringLiteral("Freedesktop"))) { 0141 return true; 0142 } 0143 #elif defined(Q_OS_MAC) 0144 if (setBackendIfAvailible(QStringLiteral("OSX Notification Center"))) { 0145 return true; 0146 } 0147 if (setBackendIfAvailible(QStringLiteral("Growl"))) { 0148 return true; 0149 } 0150 #endif 0151 if (setBackendIfAvailible(QStringLiteral("Snore"))) { 0152 return true; 0153 } 0154 return false; 0155 } 0156 0157 void SnoreCorePrivate::init() 0158 { 0159 setDefaultSettingsValueIntern(QStringLiteral("Timeout"), 10); 0160 setDefaultSettingsValueIntern(QStringLiteral("Silent"), false); 0161 m_defaultApp = Application(QStringLiteral("SnoreNotify"), Icon::defaultIcon()); 0162 } 0163 0164 void SnoreCorePrivate::setDefaultSettingsValueIntern(const QString &key, const QVariant &value) 0165 { 0166 QString nk = normalizeSettingsKey(key + QLatin1String("-SnoreDefault"), LocalSetting); 0167 if (!m_settings->contains(nk)) { 0168 m_settings->setValue(nk, value); 0169 } 0170 } 0171 0172 void SnoreCorePrivate::syncSettings() 0173 { 0174 Q_Q(SnoreCore); 0175 QString newBackend = q->settingsValue(Constants::SettingsKeys::PrimaryBackend).toString(); 0176 if (!newBackend.isEmpty()) { 0177 QString oldBackend; 0178 if (m_notificationBackend) { 0179 oldBackend = m_notificationBackend->name(); 0180 m_notificationBackend->disable(); 0181 m_notificationBackend = nullptr; 0182 } 0183 if (!setBackendIfAvailible(newBackend)) { 0184 qCWarning(SNORE) << "Failed to set new backend" << q->settingsValue(Constants::SettingsKeys::PrimaryBackend).toString() << "restoring" << oldBackend; 0185 setBackendIfAvailible(oldBackend); 0186 } 0187 } 0188 0189 auto types = SnorePlugin::types(); 0190 types.removeOne(SnorePlugin::Backend); 0191 foreach(auto type, types) { 0192 foreach(auto & pluginName, m_pluginNames[type]) { 0193 auto key = qMakePair(type, pluginName); 0194 SnorePlugin *plugin = m_plugins.value(key); 0195 bool enable = m_plugins[key]->settingsValue(Constants::SettingsKeys::Enabled).toBool(); 0196 plugin->setEnabled(enable); 0197 } 0198 } 0199 } 0200 0201 QSettings &SnoreCorePrivate::settings() 0202 { 0203 return *m_settings; 0204 } 0205 0206 void SnoreCorePrivate::setLocalSttingsPrefix(const QString &prefix) 0207 { 0208 m_localSettingsPrefix = prefix; 0209 init(); 0210 syncSettings(); 0211 } 0212 0213 QString SnoreCorePrivate::tempPath() 0214 { 0215 #if 1 0216 static QTemporaryDir dir; 0217 return dir.path(); 0218 #else 0219 return QDir::temp().path() + QLatin1String("/libsnore/"); 0220 #endif 0221 } 0222 0223 int SnoreCorePrivate::maxNumberOfActiveNotifications() const 0224 { 0225 return m_notificationBackend ? m_notificationBackend->maxNumberOfActiveNotifications() : 3; 0226 } 0227 0228 // TODO: this is somehow horrible code 0229 SnoreCorePrivate *SnoreCorePrivate::instance() 0230 { 0231 return SnoreCore::instance().d_ptr; 0232 } 0233 0234 bool SnoreCorePrivate::primaryBackendCanUpdateNotification() const 0235 { 0236 return m_notificationBackend->canUpdateNotification(); 0237 } 0238 0239 void SnoreCorePrivate::slotNotificationClosed(Notification n) 0240 { 0241 Q_Q(SnoreCore); 0242 emit q->notificationClosed(n); 0243 if (!n.removeActiveIn(q)) { 0244 qCWarning(SNORE) << n << "was already closed"; 0245 } 0246 if (!m_notificationQue.isEmpty() && m_activeNotifications.size() < maxNumberOfActiveNotifications()) { 0247 qCDebug(SNORE) << "Broadcast from queue" << m_notificationQue.size(); 0248 q->broadcastNotification(m_notificationQue.takeFirst()); 0249 } 0250 } 0251 0252 void SnoreCorePrivate::slotAboutToQuit() 0253 { 0254 for (PluginContainer *p : PluginContainer::pluginCache(SnorePlugin::All)) { 0255 if (p->isLoaded()) { 0256 qCDebug(SNORE) << "deinitialize" << p->name(); 0257 p->load()->disable(); 0258 } 0259 } 0260 } 0261 0262 void SnoreCorePrivate::startNotificationTimeoutTimer(Notification notification) 0263 { 0264 Q_Q(SnoreCore); 0265 if (notification.isSticky()) { 0266 return; 0267 } 0268 0269 notification.data()->stopTimeoutTimer(); 0270 QTimer *timer = new QTimer(); 0271 notification.data()->m_timeoutTimer = timer; 0272 timer->setSingleShot(true); 0273 0274 if (notification.isUpdate()) { 0275 notification.old().data()->stopTimeoutTimer(); 0276 } 0277 timer->setInterval(notification.timeout() * 1000); 0278 connect(timer, &QTimer::timeout, [q, notification]() { 0279 qCDebug(SNORE) << notification; 0280 q->requestCloseNotification(notification, Notification::TimedOut); 0281 }); 0282 timer->start(); 0283 }