on e39cdce help sign in
unity8/plugins/Unity/Indicators/indicatorsmanager.cpp
322 lines 8.8 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)
55IndicatorsManager::~IndicatorsManager()
57 unload();
61void IndicatorsManager::load()
63 unload();
64 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
66 m_fsWatcher.reset(new QFileSystemWatcher(this));
68 Q_FOREACH(const QString& xdgLocation, xdgLocations)
69 {
70 QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
71 QDir indicator_dir(indicator_path);
72 if (indicator_dir.exists())
73 {
74 // watch folder for changes.
75 m_fsWatcher->addPath(indicator_path);
77 loadDir(indicator_dir);
78 }
79 }
81 QObject::connect(m_fsWatcher.data(), SIGNAL(directoryChanged(const QString&)), this, SLOT(onDirectoryChanged(const QString&)));
82 QObject::connect(m_fsWatcher.data(), SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
83 setLoaded(true);
86void IndicatorsManager::onDirectoryChanged(const QString& directory)
88 loadDir(QDir(directory));
91void IndicatorsManager::onFileChanged(const QString& file)
93 QFileInfo file_info(file);
94 if (!file_info.exists())
95 {
96 unloadFile(file_info);
97 return;
98 }
99 else
100 {
101 loadFile(QFileInfo(file));
102 }
105void IndicatorsManager::loadDir(const QDir& dir)
107 startVerify(dir.canonicalPath());
109 QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
110 Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
111 {
112 loadFile(indicator_file);
113 }
115 endVerify(dir.canonicalPath());
118void IndicatorsManager::loadFile(const QFileInfo& file_info)
120 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
121 QString name = indicator_settings.value("Indicator Service/Name").toString();
123 auto iter = m_indicatorsData.find(name);
124 if (iter != m_indicatorsData.end())
125 {
126 QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
127 IndicatorData* currentData = (*iter);
128 currentData->m_verified = true;
130 int file_info_location = -1;
131 int current_data_location = -1;
133 QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
135 // if we've already got this indicator, we need to make sure we're not overwriting data which is
136 // from a lower priority standard path
137 QStringList xdgLocations = shellDataDirs();
138 for (int i = 0; i < xdgLocations.size(); i++)
139 {
140 QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
142 if (newFileInfoDir == indicatorDir)
143 {
144 file_info_location = i;
145 }
146 if (currentDataDir == indicatorDir)
147 {
148 current_data_location = i;
149 }
151 if (file_info_location != -1 && current_data_location != -1)
152 {
153 break;
154 }
155 }
157 // file location is higher (or of equal) priority. overwrite.
158 if (file_info_location <= current_data_location &&
159 file_info != currentData->m_fileInfo)
160 {
161 currentData->m_fileInfo = file_info;
162 Q_EMIT indicatorLoaded(name);
163 }
164 }
165 else
166 {
167 IndicatorData* data = new IndicatorData(name, file_info);
168 data->m_verified = true;
169 m_indicatorsData[name]= data;
170 Q_EMIT indicatorLoaded(name);
171 }
174void IndicatorsManager::unload()
176 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
177 while(iter.hasNext())
178 {
179 iter.next();
180 Q_EMIT indicatorAboutToBeUnloaded(iter.key());
181 }
183 qDeleteAll(m_indicatorsData);
184 m_indicatorsData.clear();
186 setLoaded(false);
189void IndicatorsManager::unloadFile(const QFileInfo& file)
191 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
192 while(iter.hasNext())
193 {
194 iter.next();
195 IndicatorData* data = iter.value();
196 if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
197 {
198 if (!data->m_verified)
199 {
200 QString name = data->m_name;
201 Q_EMIT indicatorAboutToBeUnloaded(name);
203 delete data;
204 iter.remove();
205 }
206 }
207 }
209 setLoaded(m_indicatorsData.size() > 0);
212void IndicatorsManager::setLoaded(bool loaded)
214 if (loaded != m_loaded)
215 {
216 m_loaded = loaded;
217 Q_EMIT loadedChanged(m_loaded);
219 auto upstartsession = qgetenv("UPSTART_SESSION");
220 NihDBusProxy * upstart = NULL;
222 if (!upstartsession.isNull()) {
223 DBusConnection * conn = NULL;
224 conn = dbus_connection_open(upstartsession.constData(), NULL);
225 if (conn != NULL) {
226 upstart = nih_dbus_proxy_new(NULL, conn,
227 NULL,
228 DBUS_PATH_UPSTART,
229 NULL, NULL);
230 dbus_connection_unref(conn);
231 }
232 }
234 if (upstart != NULL) {
235 int event_sent = 0;
236 if (m_loaded) {
237 event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-start", NULL, 0);
238 } else {
239 event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-end", NULL, 0);
240 }
242 if (event_sent != 0) {
243 qWarning() << "Unable to send indicator event to Upstart";
244 }
245 nih_unref(upstart, NULL);
246 upstart = NULL;
247 }
248 }
251void IndicatorsManager::startVerify(const QString& path)
253 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
254 while(iter.hasNext())
255 {
256 iter.next();
257 IndicatorData* data = iter.value();
258 if (data->m_fileInfo.canonicalPath() == path)
259 {
260 data->m_verified = false;
261 }
262 }
265void IndicatorsManager::endVerify(const QString& path)
267 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
268 while(iter.hasNext())
269 {
270 iter.next();
271 IndicatorData* data = iter.value();
272 if (data->m_fileInfo.canonicalPath() == path)
273 {
274 if (!data->m_verified)
275 {
276 QString name = data->m_name;
277 Q_EMIT indicatorAboutToBeUnloaded(name);
279 delete data;
280 iter.remove();
281 }
282 }
283 }
286Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
288 if (!m_indicatorsData.contains(indicator_name))
289 {
290 qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
291 return Indicator::Ptr();
292 }
294 IndicatorData *data = m_indicatorsData[indicator_name];
295 if (data->m_indicator)
296 {
297 return data->m_indicator;
298 }
300 Indicator::Ptr new_indicator(new Indicator(this));
301 data->m_indicator = new_indicator;
302 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
303 new_indicator->init(profile, data->m_fileInfo.fileName(), settings);
304 return new_indicator;
307QList<Indicator::Ptr> IndicatorsManager::indicators()
309 QList<Indicator::Ptr> list;
310 Q_FOREACH(IndicatorData* data, m_indicatorsData)
311 {
312 Indicator::Ptr ret = indicator(data->m_name);
313 if (ret)
314 list.append(ret);
315 }
316 return list;
319bool IndicatorsManager::isLoaded() const
321 return m_loaded;