on 2492425 help sign in
unity8/plugins/Unity/Indicators/indicatorsmanager.cpp
323 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>
30class IndicatorsManager::IndicatorData
32public:
33 IndicatorData(const QString& name, const QFileInfo& fileInfo)
34 : m_name(name)
35 , m_fileInfo(fileInfo)
36 , m_verified (true)
37 {
38 }
40 QString m_name;
41 QFileInfo m_fileInfo;
43 bool m_verified;
44 Indicator::Ptr m_indicator;
45};
47IndicatorsManager::IndicatorsManager(QObject* parent)
48 : QObject(parent)
49 , m_loaded(false)
50 , m_profile("phone")
54IndicatorsManager::~IndicatorsManager()
56 unload();
60void IndicatorsManager::load(const QString& profile)
62 unload();
63 m_profile = profile;
65 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
67 m_fsWatcher.reset(new QFileSystemWatcher(this));
69 Q_FOREACH(const QString& xdgLocation, xdgLocations)
70 {
71 QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
72 QDir indicator_dir(indicator_path);
73 if (indicator_dir.exists())
74 {
75 // watch folder for changes.
76 m_fsWatcher->addPath(indicator_path);
78 loadDir(indicator_dir);
79 }
80 }
82 QObject::connect(m_fsWatcher.data(), SIGNAL(directoryChanged(const QString&)), this, SLOT(onDirectoryChanged(const QString&)));
83 QObject::connect(m_fsWatcher.data(), SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
84 setLoaded(true);
87void IndicatorsManager::onDirectoryChanged(const QString& directory)
89 loadDir(QDir(directory));
92void IndicatorsManager::onFileChanged(const QString& file)
94 QFileInfo file_info(file);
95 if (!file_info.exists())
96 {
97 unloadFile(file_info);
98 return;
99 }
100 else
101 {
102 loadFile(QFileInfo(file));
103 }
106void IndicatorsManager::loadDir(const QDir& dir)
108 startVerify(dir.canonicalPath());
110 QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
111 Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
112 {
113 loadFile(indicator_file);
114 }
116 endVerify(dir.canonicalPath());
119void IndicatorsManager::loadFile(const QFileInfo& file_info)
121 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
122 QString name = indicator_settings.value("Indicator Service/Name").toString();
124 auto iter = m_indicatorsData.find(name);
125 if (iter != m_indicatorsData.end())
126 {
127 QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
128 IndicatorData* currentData = (*iter);
129 currentData->m_verified = true;
131 int file_info_location = -1;
132 int current_data_location = -1;
134 QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
136 // if we've already got this indicator, we need to make sure we're not overwriting data which is
137 // from a lower priority standard path
138 QStringList xdgLocations = shellDataDirs();
139 for (int i = 0; i < xdgLocations.size(); i++)
140 {
141 QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
143 if (newFileInfoDir == indicatorDir)
144 {
145 file_info_location = i;
146 }
147 if (currentDataDir == indicatorDir)
148 {
149 current_data_location = i;
150 }
152 if (file_info_location != -1 && current_data_location != -1)
153 {
154 break;
155 }
156 }
158 // file location is higher (or of equal) priority. overwrite.
159 if (file_info_location <= current_data_location &&
160 file_info != currentData->m_fileInfo)
161 {
162 currentData->m_fileInfo = file_info;
163 Q_EMIT indicatorLoaded(name);
164 }
165 }
166 else
167 {
168 IndicatorData* data = new IndicatorData(name, file_info);
169 data->m_verified = true;
170 m_indicatorsData[name]= data;
171 Q_EMIT indicatorLoaded(name);
172 }
175void IndicatorsManager::unload()
177 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
178 while(iter.hasNext())
179 {
180 iter.next();
181 Q_EMIT indicatorAboutToBeUnloaded(iter.key());
182 }
184 qDeleteAll(m_indicatorsData);
185 m_indicatorsData.clear();
187 setLoaded(false);
190void IndicatorsManager::unloadFile(const QFileInfo& file)
192 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
193 while(iter.hasNext())
194 {
195 iter.next();
196 IndicatorData* data = iter.value();
197 if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
198 {
199 if (!data->m_verified)
200 {
201 QString name = data->m_name;
202 Q_EMIT indicatorAboutToBeUnloaded(name);
204 delete data;
205 iter.remove();
206 }
207 }
208 }
210 setLoaded(m_indicatorsData.size() > 0);
213void IndicatorsManager::setLoaded(bool loaded)
215 if (loaded != m_loaded)
216 {
217 m_loaded = loaded;
218 Q_EMIT loadedChanged(m_loaded);
220 auto upstartsession = qgetenv("UPSTART_SESSION");
221 NihDBusProxy * upstart = NULL;
223 if (!upstartsession.isNull()) {
224 DBusConnection * conn = NULL;
225 conn = dbus_connection_open(upstartsession.constData(), NULL);
226 if (conn != NULL) {
227 upstart = nih_dbus_proxy_new(NULL, conn,
228 NULL,
229 DBUS_PATH_UPSTART,
230 NULL, NULL);
231 dbus_connection_unref(conn);
232 }
233 }
235 if (upstart != NULL) {
236 int event_sent = 0;
237 if (m_loaded) {
238 event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-start", NULL, 0);
239 } else {
240 event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-end", NULL, 0);
241 }
243 if (event_sent != 0) {
244 qWarning() << "Unable to send indicator event to Upstart";
245 }
246 nih_unref(upstart, NULL);
247 upstart = NULL;
248 }
249 }
252void IndicatorsManager::startVerify(const QString& path)
254 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
255 while(iter.hasNext())
256 {
257 iter.next();
258 IndicatorData* data = iter.value();
259 if (data->m_fileInfo.canonicalPath() == path)
260 {
261 data->m_verified = false;
262 }
263 }
266void IndicatorsManager::endVerify(const QString& path)
268 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
269 while(iter.hasNext())
270 {
271 iter.next();
272 IndicatorData* data = iter.value();
273 if (data->m_fileInfo.canonicalPath() == path)
274 {
275 if (!data->m_verified)
276 {
277 QString name = data->m_name;
278 Q_EMIT indicatorAboutToBeUnloaded(name);
280 delete data;
281 iter.remove();
282 }
283 }
284 }
287Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
289 if (!m_indicatorsData.contains(indicator_name))
290 {
291 qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
292 return Indicator::Ptr();
293 }
295 IndicatorData *data = m_indicatorsData[indicator_name];
296 if (data->m_indicator)
297 {
298 return data->m_indicator;
299 }
301 Indicator::Ptr new_indicator(new Indicator(this));
302 data->m_indicator = new_indicator;
303 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
304 new_indicator->init(m_profile, data->m_fileInfo.fileName(), settings);
305 return new_indicator;
308QList<Indicator::Ptr> IndicatorsManager::indicators()
310 QList<Indicator::Ptr> list;
311 Q_FOREACH(IndicatorData* data, m_indicatorsData)
312 {
313 Indicator::Ptr ret = indicator(data->m_name);
314 if (ret)
315 list.append(ret);
316 }
317 return list;
320bool IndicatorsManager::isLoaded() const
322 return m_loaded;