on 04462d0 help sign in
unity8/plugins/Unity/Indicators/indicatorsmanager.cpp
326 lines 8.9 kB history raw
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Nick Dedekind <nick.dedekind@canonical.com>
17 */
19#include "indicatorsmanager.h"
21#include <QSettings>
22#include <QDebug>
24#include <upstart.h>
25#include <nih/alloc.h>
27#include "paths.h"
29const QString profile = "phone";
32class IndicatorsManager::IndicatorData
34public:
35 IndicatorData(const QString& name, const QFileInfo& fileInfo)
36 : m_name(name)
37 , m_fileInfo(fileInfo)
38 , m_verified (true)
39 {
40 }
42 QString m_name;
43 QFileInfo m_fileInfo;
45 bool m_verified;
46 Indicator::Ptr m_indicator;
47};
49IndicatorsManager::IndicatorsManager(QObject* parent)
50 : QObject(parent)
51 , m_loaded(false)
52 , m_upstart(NULL)
54 auto upstartsession = qgetenv("UPSTART_SESSION");
55 if (!upstartsession.isNull()) {
56 DBusConnection * conn = NULL;
57 conn = dbus_connection_open(upstartsession.constData(), NULL);
58 if (conn != NULL) {
59 m_upstart = nih_dbus_proxy_new(NULL, conn,
60 NULL,
61 DBUS_PATH_UPSTART,
62 NULL, NULL);
63 dbus_connection_unref(conn);
64 }
65 }
67 if (m_upstart != NULL) {
68 m_upstart->auto_start = FALSE;
69 }
72IndicatorsManager::~IndicatorsManager()
74 unload();
76 if (m_upstart != NULL) {
77 nih_unref(m_upstart, NULL);
78 m_upstart = NULL;
79 }
82void IndicatorsManager::load()
84 unload();
85 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
87 m_fsWatcher.reset(new QFileSystemWatcher(this));
89 Q_FOREACH(const QString& xdgLocation, xdgLocations)
90 {
91 QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
92 QDir indicator_dir(indicator_path);
93 if (indicator_dir.exists())
94 {
95 // watch folder for changes.
96 m_fsWatcher->addPath(indicator_path);
98 loadDir(indicator_dir);
99 }
100 }
102 QObject::connect(m_fsWatcher.data(), SIGNAL(directoryChanged(const QString&)), this, SLOT(onDirectoryChanged(const QString&)));
103 QObject::connect(m_fsWatcher.data(), SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
104 setLoaded(true);
107void IndicatorsManager::onDirectoryChanged(const QString& directory)
109 loadDir(QDir(directory));
112void IndicatorsManager::onFileChanged(const QString& file)
114 QFileInfo file_info(file);
115 if (!file_info.exists())
116 {
117 unloadFile(file_info);
118 return;
119 }
120 else
121 {
122 loadFile(QFileInfo(file));
123 }
126void IndicatorsManager::loadDir(const QDir& dir)
128 startVerify(dir.canonicalPath());
130 QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
131 Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
132 {
133 loadFile(indicator_file);
134 }
136 endVerify(dir.canonicalPath());
139void IndicatorsManager::loadFile(const QFileInfo& file_info)
141 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
142 QString name = indicator_settings.value("Indicator Service/Name").toString();
144 auto iter = m_indicatorsData.find(name);
145 if (iter != m_indicatorsData.end())
146 {
147 QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
148 IndicatorData* currentData = (*iter);
149 currentData->m_verified = true;
151 int file_info_location = -1;
152 int current_data_location = -1;
154 QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
156 // if we've already got this indicator, we need to make sure we're not overwriting data which is
157 // from a lower priority standard path
158 QStringList xdgLocations = shellDataDirs();
159 for (int i = 0; i < xdgLocations.size(); i++)
160 {
161 QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
163 if (newFileInfoDir == indicatorDir)
164 {
165 file_info_location = i;
166 }
167 if (currentDataDir == indicatorDir)
168 {
169 current_data_location = i;
170 }
172 if (file_info_location != -1 && current_data_location != -1)
173 {
174 break;
175 }
176 }
178 // file location is higher (or of equal) priority. overwrite.
179 if (file_info_location <= current_data_location &&
180 file_info != currentData->m_fileInfo)
181 {
182 currentData->m_fileInfo = file_info;
183 Q_EMIT indicatorLoaded(name);
184 }
185 }
186 else
187 {
188 IndicatorData* data = new IndicatorData(name, file_info);
189 data->m_verified = true;
190 m_indicatorsData[name]= data;
191 Q_EMIT indicatorLoaded(name);
192 }
195void IndicatorsManager::unload()
197 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
198 while(iter.hasNext())
199 {
200 iter.next();
201 Q_EMIT indicatorAboutToBeUnloaded(iter.key());
202 }
204 qDeleteAll(m_indicatorsData);
205 m_indicatorsData.clear();
207 setLoaded(false);
210void IndicatorsManager::unloadFile(const QFileInfo& file)
212 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
213 while(iter.hasNext())
214 {
215 iter.next();
216 IndicatorData* data = iter.value();
217 if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
218 {
219 if (!data->m_verified)
220 {
221 QString name = data->m_name;
222 Q_EMIT indicatorAboutToBeUnloaded(name);
224 delete data;
225 iter.remove();
226 }
227 }
228 }
230 setLoaded(m_indicatorsData.size() > 0);
233void IndicatorsManager::setLoaded(bool loaded)
235 if (loaded != m_loaded)
236 {
237 m_loaded = loaded;
238 Q_EMIT loadedChanged(m_loaded);
240 if (m_upstart != NULL) {
241 int event_sent = 0;
242 if (m_loaded) {
243 event_sent = upstart_emit_event_sync(NULL, m_upstart, "indicator-services-start", NULL, 0);
244 } else {
245 event_sent = upstart_emit_event_sync(NULL, m_upstart, "indicator-services-end", NULL, 0);
246 }
248 if (event_sent != 0) {
249 qWarning() << "Unable to send indicator event to Upstart";
250 }
251 }
252 }
255void IndicatorsManager::startVerify(const QString& path)
257 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
258 while(iter.hasNext())
259 {
260 iter.next();
261 IndicatorData* data = iter.value();
262 if (data->m_fileInfo.canonicalPath() == path)
263 {
264 data->m_verified = false;
265 }
266 }
269void IndicatorsManager::endVerify(const QString& path)
271 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
272 while(iter.hasNext())
273 {
274 iter.next();
275 IndicatorData* data = iter.value();
276 if (data->m_fileInfo.canonicalPath() == path)
277 {
278 if (!data->m_verified)
279 {
280 QString name = data->m_name;
281 Q_EMIT indicatorAboutToBeUnloaded(name);
283 delete data;
284 iter.remove();
285 }
286 }
287 }
290Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
292 if (!m_indicatorsData.contains(indicator_name))
293 {
294 qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
295 return Indicator::Ptr();
296 }
298 IndicatorData *data = m_indicatorsData[indicator_name];
299 if (data->m_indicator)
300 {
301 return data->m_indicator;
302 }
304 Indicator::Ptr new_indicator(new Indicator(this));
305 data->m_indicator = new_indicator;
306 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
307 new_indicator->init(profile, data->m_fileInfo.fileName(), settings);
308 return new_indicator;
311QList<Indicator::Ptr> IndicatorsManager::indicators()
313 QList<Indicator::Ptr> list;
314 Q_FOREACH(IndicatorData* data, m_indicatorsData)
315 {
316 Indicator::Ptr ret = indicator(data->m_name);
317 if (ret)
318 list.append(ret);
319 }
320 return list;
323bool IndicatorsManager::isLoaded() const
325 return m_loaded;