on 090a35c help sign in
unity8/plugins/Unity/Indicators/indicatorsmanager.cpp
328 lines 9.0 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 default_profile = "phone";
31class IndicatorsManager::IndicatorData
33public:
34 IndicatorData(const QString& name, const QFileInfo& fileInfo)
35 : m_name(name)
36 , m_fileInfo(fileInfo)
37 , m_verified (true)
38 {
39 }
41 QString m_name;
42 QFileInfo m_fileInfo;
44 bool m_verified;
45 Indicator::Ptr m_indicator;
46};
48IndicatorsManager::IndicatorsManager(QObject* parent)
49 : QObject(parent)
50 , m_loaded(false)
51 , m_profile("phone")
55IndicatorsManager::~IndicatorsManager()
57 unload();
61void IndicatorsManager::load(const QString& profile)
63 unload();
64 m_profile = profile;
66 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
68 m_fsWatcher.reset(new QFileSystemWatcher(this));
70 Q_FOREACH(const QString& xdgLocation, xdgLocations)
71 {
72 QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
73 QDir indicator_dir(indicator_path);
74 if (indicator_dir.exists())
75 {
76 // watch folder for changes.
77 m_fsWatcher->addPath(indicator_path);
79 loadDir(indicator_dir);
80 }
81 }
83 QObject::connect(m_fsWatcher.data(), SIGNAL(directoryChanged(const QString&)), this, SLOT(onDirectoryChanged(const QString&)));
84 QObject::connect(m_fsWatcher.data(), SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
85 setLoaded(true);
88void IndicatorsManager::onDirectoryChanged(const QString& directory)
90 loadDir(QDir(directory));
93void IndicatorsManager::onFileChanged(const QString& file)
95 QFileInfo file_info(file);
96 if (!file_info.exists())
97 {
98 unloadFile(file_info);
99 return;
100 }
101 else
102 {
103 loadFile(QFileInfo(file));
104 }
107void IndicatorsManager::loadDir(const QDir& dir)
109 startVerify(dir.canonicalPath());
111 QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
112 Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
113 {
114 loadFile(indicator_file);
115 }
117 endVerify(dir.canonicalPath());
120void IndicatorsManager::loadFile(const QFileInfo& file_info)
122 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
123 QString name = indicator_settings.value("Indicator Service/Name").toString();
125 auto iter = m_indicatorsData.find(name);
126 if (iter != m_indicatorsData.end())
127 {
128 QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
129 IndicatorData* currentData = (*iter);
130 currentData->m_verified = true;
132 int file_info_location = -1;
133 int current_data_location = -1;
135 QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
137 // if we've already got this indicator, we need to make sure we're not overwriting data which is
138 // from a lower priority standard path
139 QStringList xdgLocations = shellDataDirs();
140 for (int i = 0; i < xdgLocations.size(); i++)
141 {
142 QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
144 if (newFileInfoDir == indicatorDir)
145 {
146 file_info_location = i;
147 }
148 if (currentDataDir == indicatorDir)
149 {
150 current_data_location = i;
151 }
153 if (file_info_location != -1 && current_data_location != -1)
154 {
155 break;
156 }
157 }
159 // file location is higher (or of equal) priority. overwrite.
160 if (file_info_location <= current_data_location &&
161 file_info != currentData->m_fileInfo)
162 {
163 currentData->m_fileInfo = file_info;
164 Q_EMIT indicatorLoaded(name);
165 }
166 }
167 else
168 {
169 IndicatorData* data = new IndicatorData(name, file_info);
170 data->m_verified = true;
171 m_indicatorsData[name]= data;
172 Q_EMIT indicatorLoaded(name);
173 }
176void IndicatorsManager::unload()
178 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
179 while(iter.hasNext())
180 {
181 iter.next();
182 Q_EMIT indicatorAboutToBeUnloaded(iter.key());
183 }
185 qDeleteAll(m_indicatorsData);
186 m_indicatorsData.clear();
188 setLoaded(false);
191void IndicatorsManager::unloadFile(const QFileInfo& file)
193 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
194 while(iter.hasNext())
195 {
196 iter.next();
197 IndicatorData* data = iter.value();
198 if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
199 {
200 if (!data->m_verified)
201 {
202 QString name = data->m_name;
203 Q_EMIT indicatorAboutToBeUnloaded(name);
205 delete data;
206 iter.remove();
207 }
208 }
209 }
211 setLoaded(m_indicatorsData.size() > 0);
214void IndicatorsManager::setLoaded(bool loaded)
216 if (loaded != m_loaded)
217 {
218 m_loaded = loaded;
219 Q_EMIT loadedChanged(m_loaded);
221 auto upstartsession = qgetenv("UPSTART_SESSION");
222 NihDBusProxy * upstart = NULL;
224 if (!upstartsession.isNull()) {
225 DBusConnection * conn = NULL;
226 conn = dbus_connection_open(upstartsession.constData(), NULL);
227 if (conn != NULL) {
228 upstart = nih_dbus_proxy_new(NULL, conn,
229 NULL,
230 DBUS_PATH_UPSTART,
231 NULL, NULL);
232 dbus_connection_unref(conn);
233 }
234 }
236 if (upstart != NULL) {
237 int event_sent = 0;
238 if (m_loaded) {
239 event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-start", NULL, 0);
240 } else {
241 event_sent = upstart_emit_event_sync(NULL, upstart, "indicator-services-end", NULL, 0);
242 }
244 if (event_sent != 0) {
245 qWarning() << "Unable to send indicator event to Upstart";
246 }
247 nih_unref(upstart, NULL);
248 upstart = NULL;
249 }
250 }
253void IndicatorsManager::startVerify(const QString& path)
255 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
256 while(iter.hasNext())
257 {
258 iter.next();
259 IndicatorData* data = iter.value();
260 if (data->m_fileInfo.canonicalPath() == path)
261 {
262 data->m_verified = false;
263 }
264 }
267void IndicatorsManager::endVerify(const QString& path)
269 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
270 while(iter.hasNext())
271 {
272 iter.next();
273 IndicatorData* data = iter.value();
274 if (data->m_fileInfo.canonicalPath() == path)
275 {
276 if (!data->m_verified)
277 {
278 QString name = data->m_name;
279 Q_EMIT indicatorAboutToBeUnloaded(name);
281 delete data;
282 iter.remove();
283 }
284 }
285 }
288Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
290 if (!m_indicatorsData.contains(indicator_name))
291 {
292 qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
293 return Indicator::Ptr();
294 }
296 IndicatorData *data = m_indicatorsData[indicator_name];
297 if (data->m_indicator)
298 {
299 return data->m_indicator;
300 }
302 QString profile = qgetenv("UNITY8_INDICATOR_PROFILE");
303 if (profile.isEmpty())
304 profile = default_profile;
306 Indicator::Ptr new_indicator(new Indicator(this));
307 data->m_indicator = new_indicator;
308 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
309 new_indicator->init(m_profile, data->m_fileInfo.fileName(), settings);
310 return new_indicator;
313QList<Indicator::Ptr> IndicatorsManager::indicators()
315 QList<Indicator::Ptr> list;
316 Q_FOREACH(IndicatorData* data, m_indicatorsData)
317 {
318 Indicator::Ptr ret = indicator(data->m_name);
319 if (ret)
320 list.append(ret);
321 }
322 return list;
325bool IndicatorsManager::isLoaded() const
327 return m_loaded;