on 6f2eb61 help sign in
unity8/plugins/Unity/Indicators/indicatorsmanager.cpp
318 lines 8.7 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 <nih/alloc.h>
26#include "paths.h"
29class IndicatorsManager::IndicatorData
31public:
32 IndicatorData(const QString& name, const QFileInfo& fileInfo)
33 : m_name(name)
34 , m_fileInfo(fileInfo)
35 , m_verified (true)
36 {
37 }
39 QString m_name;
40 QFileInfo m_fileInfo;
42 bool m_verified;
43 Indicator::Ptr m_indicator;
44};
46IndicatorsManager::IndicatorsManager(QObject* parent)
47 : QObject(parent)
48 , m_loaded(false)
49 , m_upstart(NULL)
51 auto upstartsession = qgetenv("UPSTART_SESSION");
52 if (!upstartsession.isNull()) {
53 DBusConnection * conn = NULL;
54 conn = dbus_connection_open(upstartsession.constData(), NULL);
55 if (conn != NULL) {
56 m_upstart = nih_dbus_proxy_new(NULL, conn,
57 NULL,
58 DBUS_PATH_UPSTART,
59 NULL, NULL);
60 dbus_connection_unref(conn);
61 }
62 }
64 if (m_upstart != NULL) {
65 m_upstart->auto_start = FALSE;
66 }
69IndicatorsManager::~IndicatorsManager()
71 unload();
73 if (m_upstart != NULL) {
74 nih_unref(m_upstart, NULL);
75 m_upstart = NULL;
76 }
79void IndicatorsManager::load()
81 unload();
82 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
84 m_fsWatcher.reset(new QFileSystemWatcher(this));
86 Q_FOREACH(const QString& xdgLocation, xdgLocations)
87 {
88 QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
89 QDir indicator_dir(indicator_path);
90 if (indicator_dir.exists())
91 {
92 // watch folder for changes.
93 m_fsWatcher->addPath(indicator_path);
95 loadDir(indicator_dir);
96 }
97 }
99 QObject::connect(m_fsWatcher.data(), SIGNAL(directoryChanged(const QString&)), this, SLOT(onDirectoryChanged(const QString&)));
100 QObject::connect(m_fsWatcher.data(), SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
101 setLoaded(true);
104void IndicatorsManager::onDirectoryChanged(const QString& directory)
106 loadDir(QDir(directory));
109void IndicatorsManager::onFileChanged(const QString& file)
111 QFileInfo file_info(file);
112 if (!file_info.exists())
113 {
114 unloadFile(file_info);
115 return;
116 }
117 else
118 {
119 loadFile(QFileInfo(file));
120 }
123void IndicatorsManager::loadDir(const QDir& dir)
125 startVerify(dir.canonicalPath());
127 QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
128 Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
129 {
130 loadFile(indicator_file);
131 }
133 endVerify(dir.canonicalPath());
136void IndicatorsManager::loadFile(const QFileInfo& file_info)
138 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
139 QString name = indicator_settings.value("Indicator Service/Name").toString();
141 auto iter = m_indicatorsData.find(name);
142 if (iter != m_indicatorsData.end())
143 {
144 QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
145 IndicatorData* currentData = (*iter);
146 currentData->m_verified = true;
148 int file_info_location = -1;
149 int current_data_location = -1;
151 QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
153 // if we've already got this indicator, we need to make sure we're not overwriting data which is
154 // from a lower priority standard path
155 QStringList xdgLocations = shellDataDirs();
156 for (int i = 0; i < xdgLocations.size(); i++)
157 {
158 QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
160 if (newFileInfoDir == indicatorDir)
161 {
162 file_info_location = i;
163 }
164 if (currentDataDir == indicatorDir)
165 {
166 current_data_location = i;
167 }
169 if (file_info_location != -1 && current_data_location != -1)
170 {
171 break;
172 }
173 }
175 // file location is higher (or of equal) priority. overwrite.
176 if (file_info_location <= current_data_location &&
177 file_info != currentData->m_fileInfo)
178 {
179 currentData->m_fileInfo = file_info;
180 Q_EMIT indicatorLoaded(name);
181 }
182 }
183 else
184 {
185 IndicatorData* data = new IndicatorData(name, file_info);
186 data->m_verified = true;
187 m_indicatorsData[name]= data;
188 Q_EMIT indicatorLoaded(name);
189 }
192void IndicatorsManager::unload()
194 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
195 while(iter.hasNext())
196 {
197 iter.next();
198 Q_EMIT indicatorAboutToBeUnloaded(iter.key());
199 }
201 qDeleteAll(m_indicatorsData);
202 m_indicatorsData.clear();
204 setLoaded(false);
207void IndicatorsManager::unloadFile(const QFileInfo& file)
209 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
210 while(iter.hasNext())
211 {
212 iter.next();
213 IndicatorData* data = iter.value();
214 if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
215 {
216 if (!data->m_verified)
217 {
218 QString name = data->m_name;
219 Q_EMIT indicatorAboutToBeUnloaded(name);
221 delete data;
222 iter.remove();
223 }
224 }
225 }
227 setLoaded(m_indicatorsData.size() > 0);
230void IndicatorsManager::setLoaded(bool loaded)
232 if (loaded != m_loaded)
233 {
234 m_loaded = loaded;
235 Q_EMIT loadedChanged(m_loaded);
237 DBusPendingCall * pending = NULL;
238 if (m_loaded) {
239 pending = upstart_emit_event(m_upstart, "indicator-services-start", NULL, 0, NULL, NULL, NULL, 100);
240 } else {
241 pending = upstart_emit_event(m_upstart, "indicator-services-end", NULL, 0, NULL, NULL, NULL, 100);
242 }
243 dbus_pending_call_unref(pending);
244 }
247void IndicatorsManager::startVerify(const QString& path)
249 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
250 while(iter.hasNext())
251 {
252 iter.next();
253 IndicatorData* data = iter.value();
254 if (data->m_fileInfo.canonicalPath() == path)
255 {
256 data->m_verified = false;
257 }
258 }
261void IndicatorsManager::endVerify(const QString& path)
263 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
264 while(iter.hasNext())
265 {
266 iter.next();
267 IndicatorData* data = iter.value();
268 if (data->m_fileInfo.canonicalPath() == path)
269 {
270 if (!data->m_verified)
271 {
272 QString name = data->m_name;
273 Q_EMIT indicatorAboutToBeUnloaded(name);
275 delete data;
276 iter.remove();
277 }
278 }
279 }
282Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
284 if (!m_indicatorsData.contains(indicator_name))
285 {
286 qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
287 return Indicator::Ptr();
288 }
290 IndicatorData *data = m_indicatorsData[indicator_name];
291 if (data->m_indicator)
292 {
293 return data->m_indicator;
294 }
296 Indicator::Ptr new_indicator(new Indicator(this));
297 data->m_indicator = new_indicator;
298 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
299 new_indicator->init(data->m_fileInfo.fileName(), settings);
300 return new_indicator;
303QList<Indicator::Ptr> IndicatorsManager::indicators()
305 QList<Indicator::Ptr> list;
306 Q_FOREACH(IndicatorData* data, m_indicatorsData)
307 {
308 Indicator::Ptr ret = indicator(data->m_name);
309 if (ret)
310 list.append(ret);
311 }
312 return list;
315bool IndicatorsManager::isLoaded() const
317 return m_loaded;