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