37
38
m_clickPackages = buildClickList();
40
/* Look through `hooks' for a desktop file in `directory'
41
/* Look through `hooks' for a desktop or ini file in `directory'
41
42
* and set the display name and icon from this.
43
* Will set with information from the first desktop file found and parsed.
44
* Will set with information from the first desktop or ini file found and parsed.
45
void ClickModel::populateFromDesktopFile (Click *newClick,
46
void ClickModel::populateFromDesktopOrIniFile (Click *newClick,
49
50
QVariantMap appHooks;
50
51
GKeyFile *appinfo = g_key_file_new();
51
gchar *desktopFileName = NULL;
52
gchar *desktopOrIniFileName = nullptr;
53
54
QVariantMap::ConstIterator begin(hooks.constBegin());
54
55
QVariantMap::ConstIterator end(hooks.constEnd());
57
const gchar *keyGroup = G_KEY_FILE_DESKTOP_GROUP;
58
const gchar *keyName = G_KEY_FILE_DESKTOP_KEY_NAME;
56
60
// Look through the hooks for a 'desktop' key which points to a desktop
57
// file referring to this app.
61
// file referring to this app, or a 'scope' key pointing to an ini
58
62
while (begin != end) {
59
63
appHooks = (*begin++).toMap();
60
64
if (!appHooks.isEmpty() &&
61
appHooks.contains("desktop") &&
65
(appHooks.contains("desktop") || appHooks.contains("scope")) &&
62
66
directory.exists()) {
63
QFile desktopFile(directory.absoluteFilePath(
64
appHooks.value("desktop", "undefined").toString()));
67
g_strdup(desktopFile.fileName().toLocal8Bit().constData());
69
g_debug ("Desktop file: %s", desktopFileName);
71
if (!desktopFile.exists())
68
if (appHooks.contains("scope"))
70
keyGroup = "ScopeConfig";
71
keyName = "DisplayName";
74
directory.absoluteFilePath(appHooks.value("scope", "").toString()));
75
scopeDirectory.setNameFilters(QStringList()<<"*.ini");
77
QStringList iniEntry(scopeDirectory.entryList());
79
if (iniEntry.isEmpty())
82
QFile desktopOrIniFile(scopeDirectory.absoluteFilePath(iniEntry[0]));
83
desktopOrIniFileName =
84
g_strdup(desktopOrIniFile.fileName().toLocal8Bit().constData());
85
if (!desktopOrIniFile.exists())
88
/* replace directory so the icon is correctly loaded */
89
directory = scopeDirectory;
93
keyGroup = G_KEY_FILE_DESKTOP_GROUP;
94
keyName = G_KEY_FILE_DESKTOP_KEY_NAME;
96
QFile desktopOrIniFile(directory.absoluteFilePath(
97
appHooks.value("desktop", "undefined").toString()));
99
desktopOrIniFileName =
100
g_strdup(desktopOrIniFile.fileName().toLocal8Bit().constData());
102
if (!desktopOrIniFile.exists())
106
g_debug ("Desktop or ini file: %s", desktopOrIniFileName);
74
110
gboolean loaded = g_key_file_load_from_file(appinfo,
111
desktopOrIniFileName,
80
g_warning ("Couldn't parse desktop file %s", desktopFileName);
116
g_warning ("Couldn't parse desktop or ini file %s", desktopOrIniFileName);
84
gchar * name = g_key_file_get_string (appinfo,
85
G_KEY_FILE_DESKTOP_GROUP,
86
G_KEY_FILE_DESKTOP_KEY_NAME,
120
gchar * name = g_key_file_get_locale_string (appinfo,
90
127
g_debug ("Name is %s", name);
91
128
newClick->displayName = name;
96
// Overwrite the icon with the .desktop file's one if we have it.
133
// Overwrite the icon with the .desktop or ini file's one if we have it.
97
134
// This is the one that the app scope displays so use that if we
99
136
gchar * icon = g_key_file_get_string (appinfo,
100
G_KEY_FILE_DESKTOP_GROUP,
101
138
G_KEY_FILE_DESKTOP_KEY_ICON,
105
142
g_debug ("Icon is %s", icon);
139
177
// Set the icon from the click package. Might be a path or a reference to a themed icon.
140
178
QString iconFile(manifest.value("icon", "undefined").toString());
142
if (directory.exists()) {
180
if (directory.exists() && iconFile != "undefined") {
143
181
QFile icon(directory.absoluteFilePath(iconFile.simplified()));
144
182
if (!icon.exists() && QIcon::hasThemeIcon(iconFile)) // try the icon theme
145
newClick.icon = iconFile;
183
newClick.icon = QString("image://theme/%1").arg(iconFile);
147
185
newClick.icon = icon.fileName();
152
// "hooks" → title → "desktop" / "icon"
190
// "hooks" → title → "desktop" or "ini" / "icon"
153
191
QVariant hooks(manifest.value("hooks"));
155
193
if (hooks.isValid()) {
156
194
QVariantMap allHooks(hooks.toMap());
157
// The desktop file contains an icon and the display name
158
populateFromDesktopFile(&newClick, allHooks, directory);
195
// The desktop or ini file contains an icon and the display name
196
populateFromDesktopOrIniFile(&newClick, allHooks, directory);
161
199
newClick.installSize = manifest.value("installed-size",
169
207
QList<ClickModel::Click> ClickModel::buildClickList()
171
QFile clickBinary("/usr/bin/click");
172
if (!clickBinary.exists()) {
173
return QList<ClickModel::Click>();
176
QProcess clickProcess;
177
clickProcess.start("/usr/bin/click",
178
QStringList() << "list" << "--all" << "--manifest");
180
if (!clickProcess.waitForFinished(5000)) {
181
qWarning() << "Timeout retrieving the list of click packages";
182
return QList<ClickModel::Click>();
185
if (clickProcess.exitStatus() == QProcess::CrashExit) {
186
qWarning() << "The click utility exited abnormally" <<
187
clickProcess.readAllStandardError();
210
GError *err = nullptr;
211
gchar *clickmanifest = nullptr;
213
clickdb = click_db_new();
214
click_db_read(clickdb, nullptr, &err);
215
if (err != nullptr) {
216
g_warning("Unable to read Click database: %s", err->message);
218
g_object_unref(clickdb);
219
return QList<ClickModel::Click>();
222
clickmanifest = click_db_get_manifests_as_string(clickdb, TRUE, &err);
223
g_object_unref(clickdb);
225
if (err != nullptr) {
226
g_warning("Unable to get the manifests: %s", err->message);
188
228
return QList<ClickModel::Click>();
191
231
QJsonParseError error;
193
233
QJsonDocument jsond =
194
QJsonDocument::fromJson(clickProcess.readAllStandardOutput(),
234
QJsonDocument::fromJson(clickmanifest, &error);
235
g_free(clickmanifest);
197
237
if (error.error != QJsonParseError::NoError) {
198
238
qWarning() << error.errorString();