Merge lp:~larryprice/ubuntu-app-launch/find-theme-icons into lp:ubuntu-app-launch/16.04

Proposed by Larry Price
Status: Merged
Approved by: Ted Gould
Approved revision: 310
Merged at revision: 223
Proposed branch: lp:~larryprice/ubuntu-app-launch/find-theme-icons
Merge into: lp:ubuntu-app-launch/16.04
Prerequisite: lp:~larryprice/ubuntu-app-launch/no-display-options
Diff against target: 1124 lines (+709/-36)
17 files modified
docs/index.rst (+10/-0)
libubuntu-app-launch/CMakeLists.txt (+3/-1)
libubuntu-app-launch/application-icon-finder.cpp (+353/-0)
libubuntu-app-launch/application-icon-finder.h (+89/-0)
libubuntu-app-launch/application-impl-legacy.cpp (+18/-9)
libubuntu-app-launch/application-impl-legacy.h (+3/-1)
libubuntu-app-launch/application-impl-libertine.cpp (+16/-2)
libubuntu-app-launch/application-impl-libertine.h (+2/-1)
libubuntu-app-launch/application-info-desktop.cpp (+26/-11)
libubuntu-app-launch/application-info-desktop.h (+4/-1)
libubuntu-app-launch/application.cpp (+1/-3)
libubuntu-app-launch/application.h (+1/-1)
libubuntu-app-launch/registry-impl.cpp (+11/-0)
libubuntu-app-launch/registry-impl.h (+9/-3)
tests/CMakeLists.txt (+22/-3)
tests/application-icon-finder.cpp (+93/-0)
tests/data/usr/share/icons/hicolor/index.theme (+48/-0)
To merge this branch: bzr merge lp:~larryprice/ubuntu-app-launch/find-theme-icons
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Review via email: mp+293287@code.launchpad.net

Commit message

Update icon search for non-click applications to search the hicolor theme directory for appropriate icons.

Description of the change

Update icon search for non-click applications to search the hicolor theme directory for appropriate icons.

Icon update code is based on: https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html but finds the optimal icon based on maximum size. Accessed through the registry, and caches paths that have already been considered. For only 12 Libertine apps, caching allowed the icon fetch process to take half as much time, so I'm assuming for 120 or 1200 apps it would have an even more drastic effect. Some of the various code paths are based only on what I've observed from various desktop files, such as searching the pixmaps directory when given a file with an extension but not a path.

To post a comment you must log in.
287. By Larry Price

Removing commented line

288. By Larry Price

removing unnecessary env setup in CMakeList

Revision history for this message
Ted Gould (ted) wrote :

Overall, really cool. Love getting all of these features included into the icon searching functionality, I think you're on the right path. A couple of global comments and some inline cleanup stuff!

* Fix for ~/.local installed icons for Steam we discussed on IRC
* Please add the new Class to /docs/index.rst so it gets in the implementation documentation (doc strings are a plus as well, not everywhere yet, but trying to get more in)
* make sure to run "make format" in the lib dir, not sure if you have or not (I don't care, but lots of folks seem to, and it avoids big diffs in the future)

review: Needs Fixing
289. By Larry Price

pixmaps should be fallback for all icons - addresses firefox

290. By Larry Price

use g_build_filepath more often, update interface, better flow [recycle]

291. By Larry Price

sorting directories by size from highest to lowest

292. By Larry Price

using defined cmake source path for tests

293. By Larry Price

adding more test data and a few more tests

294. By Larry Price

running clang format

295. By Larry Price

Adding support for searching local icon directories

296. By Larry Price

adding forgotten steam icons

297. By Larry Price

updating documentation

298. By Larry Price

more documentation for public members of iconfinder

299. By Larry Price

Merge ~ted/ubuntu-app-launch/find-theme-icons-ted

300. By Larry Price

deleting unnecessary null check

301. By Larry Price

Allowing spaces in app names and undoing incorrect local dir stuff

302. By Larry Price

Merge with ted

303. By Larry Price

Fixing some small merge issues, correcting regex for matching dirs

304. By Larry Price

Fixing tests

305. By Larry Price

Merge with trunk

306. By Larry Price

no need for second capture group in regex

307. By Larry Price

Merge with ted

308. By Larry Price

Adding tests for root icons path

309. By Larry Price

running clang format on the test

310. By Larry Price

Adding missing app icons

Revision history for this message
Ted Gould (ted) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'docs/index.rst'
--- docs/index.rst 2016-04-20 21:29:37 +0000
+++ docs/index.rst 2016-05-03 14:23:08 +0000
@@ -106,6 +106,16 @@
106 :private-members:106 :private-members:
107 :undoc-members:107 :undoc-members:
108108
109Application Icon Finder
110------------------------
111
112.. doxygenclass:: ubuntu::app_launch::app_info::IconFinder
113 :project: libubuntu-app-launch
114 :members:
115 :protected-members:
116 :private-members:
117 :undoc-members:
118
109Helper Implementation Click119Helper Implementation Click
110---------------------------120---------------------------
111121
112122
=== modified file 'libubuntu-app-launch/CMakeLists.txt'
--- libubuntu-app-launch/CMakeLists.txt 2016-02-09 22:51:12 +0000
+++ libubuntu-app-launch/CMakeLists.txt 2016-05-03 14:23:08 +0000
@@ -1,4 +1,3 @@
1
2include_directories(${CMAKE_CURRENT_SOURCE_DIR})1include_directories(${CMAKE_CURRENT_SOURCE_DIR})
3include_directories(${CMAKE_CURRENT_BINARY_DIR})2include_directories(${CMAKE_CURRENT_BINARY_DIR})
43
@@ -40,9 +39,12 @@
40registry-impl.cpp39registry-impl.cpp
41application-impl-base.cpp40application-impl-base.cpp
42application-impl-click.cpp41application-impl-click.cpp
42application-impl-legacy.h
43application-impl-legacy.cpp43application-impl-legacy.cpp
44application-impl-libertine.h
44application-impl-libertine.cpp45application-impl-libertine.cpp
45application-info-desktop.cpp46application-info-desktop.cpp
47application-icon-finder.cpp
46helper-impl-click.cpp48helper-impl-click.cpp
47glib-thread.cpp49glib-thread.cpp
48)50)
4951
=== added file 'libubuntu-app-launch/application-icon-finder.cpp'
--- libubuntu-app-launch/application-icon-finder.cpp 1970-01-01 00:00:00 +0000
+++ libubuntu-app-launch/application-icon-finder.cpp 2016-05-03 14:23:08 +0000
@@ -0,0 +1,353 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Larry Price <larry.price@canonical.com>
18 */
19
20#include "application-icon-finder.h"
21#include <regex>
22
23namespace ubuntu
24{
25namespace app_launch
26{
27namespace
28{
29constexpr auto ICONS_DIR = "/icons";
30constexpr auto HICOLOR_THEME_DIR = "/icons/hicolor";
31constexpr auto HICOLOR_THEME_FILE = "/icons/hicolor/index.theme";
32constexpr auto APPLICATIONS_TYPE = "Applications";
33constexpr auto SIZE_PROPERTY = "Size";
34constexpr auto MAXSIZE_PROPERTY = "MaxSize";
35constexpr auto THRESHOLD_PROPERTY = "Threshold";
36constexpr auto FIXED_CONTEXT = "Fixed";
37constexpr auto SCALABLE_CONTEXT = "Scalable";
38constexpr auto THRESHOLD_CONTEXT = "Threshold";
39constexpr auto CONTEXT_PROPERTY = "Context";
40constexpr auto TYPE_PROPERTY = "Type";
41constexpr auto DIRECTORIES_PROPERTY = "Directories";
42constexpr auto ICON_THEME_KEY = "Icon Theme";
43constexpr auto PIXMAPS_PATH = "/pixmaps/";
44constexpr auto ICON_TYPES = {".png", ".svg", ".xpm"};
45
46static const std::regex iconSizeDirname = std::regex("^(\\d+)x\\1$");
47} // anonymous namespace
48
49IconFinder::IconFinder(std::string basePath)
50 : _searchPaths(getSearchPaths(basePath))
51 , _basePath(basePath)
52{
53}
54
55/** Finds an icon in the search paths that we have for this path */
56Application::Info::IconPath IconFinder::find(const std::string& iconName)
57{
58 if (iconName[0] == '/') // explicit icon path received
59 {
60 return Application::Info::IconPath::from_raw(iconName);
61 }
62
63 /* Look in each directory slowly decreasing the size until we find
64 an icon */
65 auto size = 0;
66 std::string iconPath;
67 for (const auto& path : _searchPaths)
68 {
69 if (path.size > size)
70 {
71 auto foundIcon = findExistingIcon(path.path, iconName);
72 if (!foundIcon.empty())
73 {
74 size = path.size;
75 iconPath = foundIcon;
76 }
77 }
78 }
79
80 return Application::Info::IconPath::from_raw(iconPath);
81}
82
83/** Check to see if this is an icon name or an icon filename */
84bool IconFinder::hasImageExtension(const char* filename)
85{
86 for (const auto& extension : ICON_TYPES)
87 {
88 if (g_str_has_suffix(filename, extension))
89 {
90 return true;
91 }
92 }
93 return false;
94}
95
96/** Check in a given path if there is an existing file in it that satifies our name */
97std::string IconFinder::findExistingIcon(const std::string& path, const std::string& iconName)
98{
99 std::string iconPath;
100
101 /* If it already has an extension, only check that one */
102 if (hasImageExtension(iconName.c_str()))
103 {
104 auto fullpath = g_build_filename(path.c_str(), iconName.c_str(), nullptr);
105 if (g_file_test(fullpath, G_FILE_TEST_EXISTS))
106 {
107 iconPath = fullpath;
108 }
109 g_free(fullpath);
110 return iconPath;
111 }
112
113 /* Otherwise check all the valid extensions to see if they exist */
114 for (const auto& extension : ICON_TYPES)
115 {
116 auto fullpath = g_build_filename(path.c_str(), (iconName + extension).c_str(), nullptr);
117 if (g_file_test(fullpath, G_FILE_TEST_EXISTS))
118 {
119 iconPath = fullpath;
120 g_free(fullpath);
121 break;
122 }
123 g_free(fullpath);
124 }
125 return iconPath;
126}
127
128/** Create a directory item if the directory exists */
129std::list<IconFinder::ThemeSubdirectory> IconFinder::validDirectories(const std::string& basePath,
130 gchar* directory,
131 int size)
132{
133 std::list<IconFinder::ThemeSubdirectory> dirs;
134 auto globalHicolorTheme = g_build_filename(basePath.c_str(), HICOLOR_THEME_DIR, directory, nullptr);
135 if (g_file_test(globalHicolorTheme, G_FILE_TEST_EXISTS))
136 {
137 dirs.emplace_back(ThemeSubdirectory{std::string(globalHicolorTheme), size});
138 }
139 g_free(globalHicolorTheme);
140
141 return dirs;
142}
143
144/** Take the data in a directory stanza and turn it into an actual directory */
145std::list<IconFinder::ThemeSubdirectory> IconFinder::addSubdirectoryByType(std::shared_ptr<GKeyFile> themefile,
146 gchar* directory,
147 const std::string& basePath)
148{
149 GError* error = nullptr;
150 auto gType = g_key_file_get_string(themefile.get(), directory, TYPE_PROPERTY, &error);
151 if (error != nullptr)
152 {
153 g_error_free(error);
154 return std::list<ThemeSubdirectory>{};
155 }
156 std::string type(gType);
157 g_free(gType);
158
159 if (type == FIXED_CONTEXT)
160 {
161 auto size = g_key_file_get_integer(themefile.get(), directory, SIZE_PROPERTY, &error);
162 if (error != nullptr)
163 {
164 g_error_free(error);
165 }
166 else
167 {
168 return validDirectories(basePath, directory, size);
169 }
170 }
171 else if (type == SCALABLE_CONTEXT)
172 {
173 auto size = g_key_file_get_integer(themefile.get(), directory, MAXSIZE_PROPERTY, &error);
174 if (error != nullptr)
175 {
176 g_error_free(error);
177 }
178 else
179 {
180 return validDirectories(basePath, directory, size);
181 }
182 }
183 else if (type == THRESHOLD_CONTEXT)
184 {
185 auto size = g_key_file_get_integer(themefile.get(), directory, SIZE_PROPERTY, &error);
186 if (error != nullptr)
187 {
188 g_error_free(error);
189 }
190 else
191 {
192 auto threshold = g_key_file_get_integer(themefile.get(), directory, THRESHOLD_PROPERTY, &error);
193 if (error != nullptr)
194 {
195 threshold = 2; // threshold defaults to 2
196 g_error_free(error);
197 }
198 return validDirectories(basePath, directory, size + threshold);
199 }
200 }
201 return std::list<ThemeSubdirectory>{};
202}
203
204/** Parse a theme file's various stanzas for each directory */
205std::list<IconFinder::ThemeSubdirectory> IconFinder::searchIconPaths(std::shared_ptr<GKeyFile> themefile,
206 gchar** directories,
207 const std::string& basePath)
208{
209 std::list<ThemeSubdirectory> subdirs;
210 for (auto i = 0; directories[i] != nullptr; ++i)
211 {
212 GError* error = nullptr;
213 auto context = g_key_file_get_string(themefile.get(), directories[i], CONTEXT_PROPERTY, &error);
214 if (error != nullptr)
215 {
216 g_error_free(error);
217 continue;
218 }
219 if (g_strcmp0(context, APPLICATIONS_TYPE) == 0)
220 {
221 auto newDirs = addSubdirectoryByType(themefile, directories[i], basePath);
222 subdirs.splice(subdirs.end(), newDirs);
223 }
224 g_free(context);
225 }
226 return subdirs;
227}
228
229/** Try to get theme subdirectories using .theme file in the hicolor theme file
230 if it exists */
231std::list<IconFinder::ThemeSubdirectory> IconFinder::themeFileSearchPaths(const std::string& basePath)
232{
233 std::string themeFilePath = basePath + HICOLOR_THEME_FILE;
234 GError* error = nullptr;
235 auto themefile = std::shared_ptr<GKeyFile>(g_key_file_new(), g_key_file_free);
236 g_key_file_load_from_file(themefile.get(), themeFilePath.c_str(), G_KEY_FILE_NONE, &error);
237 if (error != nullptr)
238 {
239 g_debug("Unable to find Hicolor theme file: %s", themeFilePath.c_str());
240 g_error_free(error);
241 return std::list<ThemeSubdirectory>();
242 }
243
244 g_key_file_set_list_separator(themefile.get(), ',');
245 auto directories =
246 g_key_file_get_string_list(themefile.get(), ICON_THEME_KEY, DIRECTORIES_PROPERTY, nullptr, &error);
247 if (error != nullptr)
248 {
249 g_debug("Hicolor theme file '%s' didn't have any directories", themeFilePath.c_str());
250 g_error_free(error);
251 return std::list<ThemeSubdirectory>();
252 }
253
254 auto iconPaths = searchIconPaths(themefile, directories, basePath);
255 g_strfreev(directories);
256 return iconPaths;
257}
258
259/** Look into a theme directory and see if we can use the subdirectories
260 as icon folders. Sadly inefficient. */
261std::list<IconFinder::ThemeSubdirectory> IconFinder::themeDirSearchPaths(const std::string& themeDir)
262{
263 std::list<IconFinder::ThemeSubdirectory> searchPaths;
264 GError* error = nullptr;
265 auto gdir = g_dir_open(themeDir.c_str(), 0, &error);
266
267 if (error != nullptr)
268 {
269 g_debug("Unable to open directory '%s' becuase: %s", themeDir.c_str(), error->message);
270 g_error_free(error);
271 return searchPaths;
272 }
273
274 const gchar* dirname = nullptr;
275 while ((dirname = g_dir_read_name(gdir)) != nullptr)
276 {
277 auto fullPath = g_build_filename(themeDir.c_str(), dirname, "apps", nullptr);
278 /* Directories only */
279 if (g_file_test(fullPath, G_FILE_TEST_IS_DIR))
280 {
281 if (g_strcmp0(dirname, "scalable") == 0)
282 {
283 /* We don't really know what to do with scalable here, let's
284 call them 256 images */
285 searchPaths.emplace_back(IconFinder::ThemeSubdirectory{fullPath, 256});
286 continue;
287 }
288
289 std::smatch match;
290 std::string dirstr(dirname);
291 /* We want it to match and have the same values for the first and second size */
292 if (std::regex_match(dirstr, match, iconSizeDirname))
293 {
294 searchPaths.emplace_back(IconFinder::ThemeSubdirectory{fullPath, std::atoi(match[1].str().c_str())});
295 }
296 }
297 g_free(fullPath);
298 }
299
300 g_dir_close(gdir);
301 return searchPaths;
302}
303
304/** Gets all the search paths, from either a theme file or just
305 looking at the directory. And possibly pixmaps as well */
306std::list<IconFinder::ThemeSubdirectory> IconFinder::getSearchPaths(const std::string& basePath)
307{
308 std::list<IconFinder::ThemeSubdirectory> iconPaths;
309
310 auto hicolorDir = g_build_filename(basePath.c_str(), HICOLOR_THEME_DIR, nullptr);
311 if (g_file_test(hicolorDir, G_FILE_TEST_IS_DIR))
312 {
313 /* If the directory exists, it could have icons of unknown size */
314 iconPaths.emplace_back(IconFinder::ThemeSubdirectory{hicolorDir, 1});
315
316 /* Now see if we can get directories from a theme file */
317 auto themeDirs = themeFileSearchPaths(basePath);
318 if (themeDirs.size() > 0)
319 {
320 iconPaths.splice(iconPaths.end(), themeDirs);
321 }
322 else
323 {
324 /* If we didn't get from a theme file, we need to manually scan the directories */
325 auto dirPaths = themeDirSearchPaths(hicolorDir);
326 iconPaths.splice(iconPaths.end(), dirPaths);
327 }
328 }
329 g_free(hicolorDir);
330
331 /* Add root icons directory as potential path */
332 auto iconsPath = g_build_filename(basePath.c_str(), ICONS_DIR, nullptr);
333 if (g_file_test(iconsPath, G_FILE_TEST_IS_DIR))
334 {
335 iconPaths.emplace_back(IconFinder::ThemeSubdirectory{iconsPath, 1});
336 }
337 g_free(iconsPath);
338
339 /* Add the pixmaps path as a fallback if it exists */
340 auto pixmapsPath = g_build_filename(basePath.c_str(), PIXMAPS_PATH, nullptr);
341 if (g_file_test(pixmapsPath, G_FILE_TEST_IS_DIR))
342 {
343 iconPaths.emplace_back(IconFinder::ThemeSubdirectory{pixmapsPath, 1});
344 }
345 g_free(pixmapsPath);
346
347 // find icons sorted by size, highest to lowest
348 iconPaths.sort([](const ThemeSubdirectory& lhs, const ThemeSubdirectory& rhs) { return lhs.size > rhs.size; });
349 return iconPaths;
350}
351
352} // namesapce app_launch
353} // namespace ubuntu
0354
=== added file 'libubuntu-app-launch/application-icon-finder.h'
--- libubuntu-app-launch/application-icon-finder.h 1970-01-01 00:00:00 +0000
+++ libubuntu-app-launch/application-icon-finder.h 2016-05-03 14:23:08 +0000
@@ -0,0 +1,89 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Larry Price <larry.price@canonical.com>
18 */
19
20#pragma once
21
22#include "application-info-desktop.h"
23#include <glib.h>
24#include <list>
25#include <map>
26#include <memory>
27
28namespace ubuntu
29{
30namespace app_launch
31{
32/** \brief Class to search for available application icons and select the best option.
33
34 This object attempts to find the highest resolution icon based on the freedesktop icon
35 theme specification found at:
36 https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
37 It parses the theme file for the hicolor theme and identifies all possible directories
38 in the global scope and the local scope.
39*/
40class IconFinder
41{
42public:
43 /** Create an IconFinder
44
45 \param basePath the root directory to begin searching for themes
46 */
47 explicit IconFinder(std::string basePath);
48 virtual ~IconFinder() = default;
49
50 /** Find the optimal icon for the given icon name.
51
52 \param iconName name of or path to application icon
53 */
54 virtual Application::Info::IconPath find(const std::string& iconName);
55
56private:
57 /** \private */
58 struct ThemeSubdirectory
59 {
60 std::string path;
61 int size;
62 };
63
64 /** \private */
65 std::list<ThemeSubdirectory> _searchPaths;
66 /** \private */
67 std::string _basePath;
68
69 /** \private */
70 static bool hasImageExtension(const char* filename);
71 /** \private */
72 static std::string findExistingIcon(const std::string& path, const std::string& iconName);
73 /** \private */
74 static std::list<ThemeSubdirectory> validDirectories(const std::string& basePath, gchar* directory, int size);
75 /** \private */
76 static std::list<ThemeSubdirectory> addSubdirectoryByType(std::shared_ptr<GKeyFile> themefile,
77 gchar* directory,
78 const std::string& basePath);
79 /** \private */
80 static std::list<ThemeSubdirectory> searchIconPaths(std::shared_ptr<GKeyFile> themefile,
81 gchar** directories,
82 const std::string& basePath);
83 static std::list<ThemeSubdirectory> themeFileSearchPaths(const std::string& basePath);
84 static std::list<ThemeSubdirectory> themeDirSearchPaths(const std::string& basePath);
85 static std::list<ThemeSubdirectory> getSearchPaths(const std::string& basePath);
86};
87
88} // namespace app_launch
89} // namesapce ubuntu
090
=== modified file 'libubuntu-app-launch/application-impl-legacy.cpp'
--- libubuntu-app-launch/application-impl-legacy.cpp 2016-03-03 20:48:24 +0000
+++ libubuntu-app-launch/application-impl-legacy.cpp 2016-05-03 14:23:08 +0000
@@ -27,7 +27,7 @@
27namespace app_impls27namespace app_impls
28{28{
2929
30std::shared_ptr<GKeyFile> keyfileForApp(const AppID::AppName& name);30std::pair<std::string, std::shared_ptr<GKeyFile>> keyfileForApp(const AppID::AppName& name);
3131
32void clear_keyfile(GKeyFile* keyfile)32void clear_keyfile(GKeyFile* keyfile)
33{33{
@@ -38,10 +38,12 @@
38}38}
3939
40Legacy::Legacy(const AppID::AppName& appname,40Legacy::Legacy(const AppID::AppName& appname,
41 const std::string& basedir,
41 const std::shared_ptr<GKeyFile>& keyfile,42 const std::shared_ptr<GKeyFile>& keyfile,
42 const std::shared_ptr<Registry>& registry)43 const std::shared_ptr<Registry>& registry)
43 : Base(registry)44 : Base(registry)
44 , _appname(appname)45 , _appname(appname)
46 , _basedir(basedir)
45 , _keyfile(keyfile)47 , _keyfile(keyfile)
46{48{
47 if (!_keyfile)49 if (!_keyfile)
@@ -49,15 +51,20 @@
49}51}
5052
51Legacy::Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry)53Legacy::Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry)
52 : Legacy(appname, keyfileForApp(appname), registry)54 : Base(registry)
55 , _appname(appname)
53{56{
57 std::tie(_basedir, _keyfile) = keyfileForApp(appname);
58
59 if (!_keyfile)
60 throw std::runtime_error{"Unable to find keyfile for legacy application: " + appname.value()};
54}61}
5562
56std::shared_ptr<GKeyFile> keyfileForApp(const AppID::AppName& name)63std::pair<std::string, std::shared_ptr<GKeyFile>> keyfileForApp(const AppID::AppName& name)
57{64{
58 std::string desktopName = name.value() + ".desktop";65 std::string desktopName = name.value() + ".desktop";
59 auto keyfilecheck = [desktopName](const gchar* dir) -> std::shared_ptr<GKeyFile> {66 auto keyfilecheck = [desktopName](const std::string& dir) -> std::shared_ptr<GKeyFile> {
60 auto fullname = g_build_filename(dir, "applications", desktopName.c_str(), nullptr);67 auto fullname = g_build_filename(dir.c_str(), "applications", desktopName.c_str(), nullptr);
61 if (!g_file_test(fullname, G_FILE_TEST_EXISTS))68 if (!g_file_test(fullname, G_FILE_TEST_EXISTS))
62 {69 {
63 g_free(fullname);70 g_free(fullname);
@@ -80,20 +87,22 @@
80 return keyfile;87 return keyfile;
81 };88 };
8289
83 auto retval = keyfilecheck(g_get_user_data_dir());90 std::string basedir = g_get_user_data_dir();
91 auto retval = keyfilecheck(basedir);
8492
85 auto systemDirs = g_get_system_data_dirs();93 auto systemDirs = g_get_system_data_dirs();
86 for (auto i = 0; !retval && systemDirs[i] != nullptr; i++)94 for (auto i = 0; !retval && systemDirs[i] != nullptr; i++)
87 {95 {
88 retval = keyfilecheck(systemDirs[i]);96 basedir = systemDirs[i];
97 retval = keyfilecheck(basedir);
89 }98 }
9099
91 return retval;100 return std::make_pair(basedir, retval);
92}101}
93102
94std::shared_ptr<Application::Info> Legacy::info()103std::shared_ptr<Application::Info> Legacy::info()
95{104{
96 return std::make_shared<app_info::Desktop>(_keyfile, "/usr/share/icons/");105 return std::make_shared<app_info::Desktop>(_keyfile, _basedir, _registry, true);
97}106}
98107
99std::list<std::shared_ptr<Application>> Legacy::list(const std::shared_ptr<Registry>& registry)108std::list<std::shared_ptr<Application>> Legacy::list(const std::shared_ptr<Registry>& registry)
100109
=== modified file 'libubuntu-app-launch/application-impl-legacy.h'
--- libubuntu-app-launch/application-impl-legacy.h 2016-02-10 15:27:10 +0000
+++ libubuntu-app-launch/application-impl-legacy.h 2016-05-03 14:23:08 +0000
@@ -35,6 +35,7 @@
35public:35public:
36 Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry);36 Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry);
37 Legacy(const AppID::AppName& appname,37 Legacy(const AppID::AppName& appname,
38 const std::string& basedir,
38 const std::shared_ptr<GKeyFile>& keyfile,39 const std::shared_ptr<GKeyFile>& keyfile,
39 const std::shared_ptr<Registry>& registry);40 const std::shared_ptr<Registry>& registry);
4041
@@ -45,10 +46,11 @@
4546
46 std::shared_ptr<Info> info() override;47 std::shared_ptr<Info> info() override;
4748
48 static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry> &registry);49 static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry);
4950
50private:51private:
51 AppID::AppName _appname;52 AppID::AppName _appname;
53 std::string _basedir;
52 std::shared_ptr<GKeyFile> _keyfile;54 std::shared_ptr<GKeyFile> _keyfile;
53};55};
5456
5557
=== modified file 'libubuntu-app-launch/application-impl-libertine.cpp'
--- libubuntu-app-launch/application-impl-libertine.cpp 2016-03-03 20:48:24 +0000
+++ libubuntu-app-launch/application-impl-libertine.cpp 2016-05-03 14:23:08 +0000
@@ -41,10 +41,17 @@
41 {41 {
42 auto container_path = libertine_container_path(container.value().c_str());42 auto container_path = libertine_container_path(container.value().c_str());
43 auto container_app_path = g_build_filename(container_path, "usr", "share", "applications",43 auto container_app_path = g_build_filename(container_path, "usr", "share", "applications",
44 (appname.value() + ".desktop").c_str(), NULL);44 (appname.value() + ".desktop").c_str(), nullptr);
4545
46 _keyfile = keyfileFromPath(container_app_path);46 _keyfile = keyfileFromPath(container_app_path);
4747
48 if (_keyfile)
49 {
50 auto gbasedir = g_build_filename(container_path, "usr", "share", nullptr);
51 _basedir = gbasedir;
52 g_free(gbasedir);
53 }
54
48 g_free(container_app_path);55 g_free(container_app_path);
49 g_free(container_path);56 g_free(container_path);
50 }57 }
@@ -57,6 +64,13 @@
5764
58 _keyfile = keyfileFromPath(home_app_path);65 _keyfile = keyfileFromPath(home_app_path);
5966
67 if (_keyfile)
68 {
69 auto gbasedir = g_build_filename(home_path, ".local", "share", nullptr);
70 _basedir = gbasedir;
71 g_free(gbasedir);
72 }
73
60 g_free(home_app_path);74 g_free(home_app_path);
61 g_free(home_path);75 g_free(home_path);
62 }76 }
@@ -119,7 +133,7 @@
119133
120std::shared_ptr<Application::Info> Libertine::info()134std::shared_ptr<Application::Info> Libertine::info()
121{135{
122 return std::make_shared<app_info::Desktop>(_keyfile, libertine_container_path(_container.value().c_str()));136 return std::make_shared<app_info::Desktop>(_keyfile, _basedir, _registry);
123}137}
124138
125}; // namespace app_impls139}; // namespace app_impls
126140
=== modified file 'libubuntu-app-launch/application-impl-libertine.h'
--- libubuntu-app-launch/application-impl-libertine.h 2016-02-10 15:38:21 +0000
+++ libubuntu-app-launch/application-impl-libertine.h 2016-05-03 14:23:08 +0000
@@ -36,7 +36,7 @@
36 const AppID::AppName& appname,36 const AppID::AppName& appname,
37 const std::shared_ptr<Registry>& registry);37 const std::shared_ptr<Registry>& registry);
3838
39 static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry> &registry);39 static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry);
4040
41 AppID appId() override41 AppID appId() override
42 {42 {
@@ -49,6 +49,7 @@
49 AppID::Package _container;49 AppID::Package _container;
50 AppID::AppName _appname;50 AppID::AppName _appname;
51 std::shared_ptr<GKeyFile> _keyfile;51 std::shared_ptr<GKeyFile> _keyfile;
52 std::string _basedir;
52};53};
5354
54}; // namespace app_impls55}; // namespace app_impls
5556
=== modified file 'libubuntu-app-launch/application-info-desktop.cpp'
--- libubuntu-app-launch/application-info-desktop.cpp 2016-05-03 14:23:08 +0000
+++ libubuntu-app-launch/application-info-desktop.cpp 2016-05-03 14:23:08 +0000
@@ -18,6 +18,8 @@
18 */18 */
1919
20#include "application-info-desktop.h"20#include "application-info-desktop.h"
21#include "application-icon-finder.h"
22#include "registry-impl.h"
21#include <cstdlib>23#include <cstdlib>
2224
23namespace ubuntu25namespace ubuntu
@@ -38,7 +40,7 @@
3840
39struct NoDisplayTag;41struct NoDisplayTag;
40typedef TypeTagger<NoDisplayTag, bool> NoDisplay;42typedef TypeTagger<NoDisplayTag, bool> NoDisplay;
41} // anonymous namespace43} // anonymous namespace
4244
43template <typename T>45template <typename T>
44auto stringFromKeyfile(std::shared_ptr<GKeyFile> keyfile, const std::string& key, const std::string& exceptionText = {})46auto stringFromKeyfile(std::shared_ptr<GKeyFile> keyfile, const std::string& key, const std::string& exceptionText = {})
@@ -134,8 +136,8 @@
134 auto results = g_key_file_get_string_list(keyfile.get(), DESKTOP_GROUP, key, nullptr, &error);136 auto results = g_key_file_get_string_list(keyfile.get(), DESKTOP_GROUP, key, nullptr, &error);
135 if (error != nullptr)137 if (error != nullptr)
136 {138 {
137 g_error_free(error);139 g_error_free(error);
138 return defaultValue;140 return defaultValue;
139 }141 }
140142
141 bool result = false;143 bool result = false;
@@ -152,8 +154,11 @@
152 return result;154 return result;
153}155}
154156
155Desktop::Desktop(std::shared_ptr<GKeyFile> keyfile, const std::string& basePath)157Desktop::Desktop(std::shared_ptr<GKeyFile> keyfile,
156 : _keyfile([keyfile]() {158 const std::string& basePath,
159 std::shared_ptr<Registry> registry,
160 bool allowNoDisplay)
161 : _keyfile([keyfile, allowNoDisplay]() {
157 if (!keyfile)162 if (!keyfile)
158 {163 {
159 throw std::runtime_error("Can not build a desktop application info object with a null keyfile");164 throw std::runtime_error("Can not build a desktop application info object with a null keyfile");
@@ -162,7 +167,7 @@
162 {167 {
163 throw std::runtime_error("Keyfile does not represent application type");168 throw std::runtime_error("Keyfile does not represent application type");
164 }169 }
165 if (boolFromKeyfile<NoDisplay>(keyfile, "NoDisplay", false).value())170 if (boolFromKeyfile<NoDisplay>(keyfile, "NoDisplay", false).value() && !allowNoDisplay)
166 {171 {
167 throw std::runtime_error("Application is not meant to be displayed");172 throw std::runtime_error("Application is not meant to be displayed");
168 }173 }
@@ -171,10 +176,13 @@
171 throw std::runtime_error("Application keyfile is hidden");176 throw std::runtime_error("Application keyfile is hidden");
172 }177 }
173 auto xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");178 auto xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
174 if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false)179 if (xdg_current_desktop != nullptr)
175 || !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true))
176 {180 {
177 throw std::runtime_error("Application is not shown in Unity");181 if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) ||
182 !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true))
183 {
184 throw std::runtime_error("Application is not shown in Unity");
185 }
178 }186 }
179187
180 return keyfile;188 return keyfile;
@@ -182,8 +190,15 @@
182 , _basePath(basePath)190 , _basePath(basePath)
183 , _name(stringFromKeyfile<Application::Info::Name>(keyfile, "Name", "Unable to get name from keyfile"))191 , _name(stringFromKeyfile<Application::Info::Name>(keyfile, "Name", "Unable to get name from keyfile"))
184 , _description(stringFromKeyfile<Application::Info::Description>(keyfile, "Comment"))192 , _description(stringFromKeyfile<Application::Info::Description>(keyfile, "Comment"))
185 , _iconPath(193 , _iconPath([keyfile, basePath, registry]() {
186 fileFromKeyfile<Application::Info::IconPath>(keyfile, basePath, "Icon", "Missing icon for desktop file"))194 if (registry != nullptr)
195 {
196 auto iconName =
197 stringFromKeyfile<Application::Info::IconPath>(keyfile, "Icon", "Missing icon for desktop file");
198 return registry->impl->getIconFinder(basePath)->find(iconName);
199 }
200 return fileFromKeyfile<Application::Info::IconPath>(keyfile, basePath, "Icon", "Missing icon for desktop file");
201 }())
187 , _splashInfo({202 , _splashInfo({
188 title : stringFromKeyfile<Application::Info::Splash::Title>(keyfile, "X-Ubuntu-Splash-Title"),203 title : stringFromKeyfile<Application::Info::Splash::Title>(keyfile, "X-Ubuntu-Splash-Title"),
189 image : fileFromKeyfile<Application::Info::Splash::Image>(keyfile, basePath, "X-Ubuntu-Splash-Image"),204 image : fileFromKeyfile<Application::Info::Splash::Image>(keyfile, basePath, "X-Ubuntu-Splash-Image"),
190205
=== modified file 'libubuntu-app-launch/application-info-desktop.h'
--- libubuntu-app-launch/application-info-desktop.h 2016-02-10 22:04:00 +0000
+++ libubuntu-app-launch/application-info-desktop.h 2016-05-03 14:23:08 +0000
@@ -33,7 +33,10 @@
33class Desktop : public Application::Info33class Desktop : public Application::Info
34{34{
35public:35public:
36 Desktop(std::shared_ptr<GKeyFile> keyfile, const std::string& basePath);36 Desktop(std::shared_ptr<GKeyFile> keyfile,
37 const std::string& basePath,
38 std::shared_ptr<Registry> registry = nullptr,
39 bool allowNoDisplay = false);
3740
38 const Application::Info::Name& name() override41 const Application::Info::Name& name() override
39 {42 {
4043
=== modified file 'libubuntu-app-launch/application.cpp'
--- libubuntu-app-launch/application.cpp 2016-04-27 14:22:39 +0000
+++ libubuntu-app-launch/application.cpp 2016-05-03 14:23:08 +0000
@@ -75,10 +75,8 @@
75{75{
76}76}
7777
78/* These are the Regex's taken from the Click Reviewer Tools
79 on Jan 16, 2016 revision 566 */
80#define REGEX_PKGNAME "([a-z0-9][a-z0-9+.-]+)"78#define REGEX_PKGNAME "([a-z0-9][a-z0-9+.-]+)"
81#define REGEX_APPNAME "([A-Za-z0-9+-.:~-]+)"79#define REGEX_APPNAME "([A-Za-z0-9+-.:~-][\\sA-Za-z0-9+-.:~-]+)"
82#define REGEX_VERSION "([\\d+:]?[A-Za-z0-9.+:~-]+?(?:-[A-Za-z0-9+.~]+)?)"80#define REGEX_VERSION "([\\d+:]?[A-Za-z0-9.+:~-]+?(?:-[A-Za-z0-9+.~]+)?)"
8381
84const std::regex full_appid_regex("^" REGEX_PKGNAME "_" REGEX_APPNAME "_" REGEX_VERSION "$");82const std::regex full_appid_regex("^" REGEX_PKGNAME "_" REGEX_APPNAME "_" REGEX_VERSION "$");
8583
=== modified file 'libubuntu-app-launch/application.h'
--- libubuntu-app-launch/application.h 2016-04-19 02:14:03 +0000
+++ libubuntu-app-launch/application.h 2016-05-03 14:23:08 +0000
@@ -38,7 +38,7 @@
38/** \brief Class to represent an application, whether running or not, and38/** \brief Class to represent an application, whether running or not, and
39 query more information about it.39 query more information about it.
4040
41 Generally the Application object represnts an Application in the system. It41 Generally the Application object represents an Application in the system. It
42 hooks up all of it's signals, finds out information about it and controls42 hooks up all of it's signals, finds out information about it and controls
43 whether it is running or not. This class is what most users of Ubuntu App43 whether it is running or not. This class is what most users of Ubuntu App
44 Launch will do the majority of their work.44 Launch will do the majority of their work.
4545
=== modified file 'libubuntu-app-launch/registry-impl.cpp'
--- libubuntu-app-launch/registry-impl.cpp 2016-03-03 20:48:24 +0000
+++ libubuntu-app-launch/registry-impl.cpp 2016-05-03 14:23:08 +0000
@@ -18,6 +18,7 @@
18 */18 */
1919
20#include "registry-impl.h"20#include "registry-impl.h"
21#include "application-icon-finder.h"
2122
22namespace ubuntu23namespace ubuntu
23{24{
@@ -34,6 +35,7 @@
34 _dbus.reset();35 _dbus.reset();
35 })36 })
36 , _registry(registry)37 , _registry(registry)
38 , _iconFinders()
37// _manager(nullptr)39// _manager(nullptr)
38{40{
39 auto cancel = thread.getCancellable();41 auto cancel = thread.getCancellable();
@@ -162,6 +164,15 @@
162 });164 });
163}165}
164166
167std::shared_ptr<IconFinder> Registry::Impl::getIconFinder(std::string basePath)
168{
169 if (_iconFinders.find(basePath) == _iconFinders.end())
170 {
171 _iconFinders[basePath] = std::make_shared<IconFinder>(basePath);
172 }
173 return _iconFinders[basePath];
174}
175
165#if 0176#if 0
166void177void
167Registry::Impl::setManager (Registry::Manager* manager)178Registry::Impl::setManager (Registry::Manager* manager)
168179
=== modified file 'libubuntu-app-launch/registry-impl.h'
--- libubuntu-app-launch/registry-impl.h 2016-04-18 18:29:32 +0000
+++ libubuntu-app-launch/registry-impl.h 2016-05-03 14:23:08 +0000
@@ -17,12 +17,12 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "glib-thread.h"
20#include "registry.h"21#include "registry.h"
21#include "glib-thread.h"
22
23#include <json-glib/json-glib.h>
24#include <click.h>22#include <click.h>
25#include <gio/gio.h>23#include <gio/gio.h>
24#include <json-glib/json-glib.h>
25#include <unordered_map>
2626
27#pragma once27#pragma once
2828
@@ -31,6 +31,8 @@
31namespace app_launch31namespace app_launch
32{32{
3333
34class IconFinder;
35
34/** \private36/** \private
35 \brief Private implementation of the Registry object37 \brief Private implementation of the Registry object
3638
@@ -55,6 +57,8 @@
5557
56 GLib::ContextThread thread;58 GLib::ContextThread thread;
5759
60 std::shared_ptr<IconFinder> getIconFinder(std::string basePath);
61
58private:62private:
59 Registry* _registry;63 Registry* _registry;
60#if 064#if 0
@@ -67,6 +71,8 @@
67 std::shared_ptr<GDBusConnection> _dbus;71 std::shared_ptr<GDBusConnection> _dbus;
6872
69 void initClick();73 void initClick();
74
75 std::unordered_map<std::string, std::shared_ptr<IconFinder>> _iconFinders;
70};76};
7177
72}; // namespace app_launch78}; // namespace app_launch
7379
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2016-02-17 21:56:34 +0000
+++ tests/CMakeLists.txt 2016-05-03 14:23:08 +0000
@@ -1,4 +1,3 @@
1
2set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
32
4configure_file ("click-db-dir/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-db-dir/test.conf" @ONLY)3configure_file ("click-db-dir/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-db-dir/test.conf" @ONLY)
@@ -60,12 +59,32 @@
60# Application Info Desktop59# Application Info Desktop
6160
62add_executable (application-info-desktop-test61add_executable (application-info-desktop-test
63 application-info-desktop.cpp62 # test
64 ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-info-desktop.cpp)63 application-info-desktop.cpp
64
65 # sources
66 ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-info-desktop.cpp
67 ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-icon-finder.cpp
68 ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/glib-thread.cpp
69 ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/registry-impl.cpp)
65target_link_libraries (application-info-desktop-test gtest ${GTEST_LIBS} ubuntu-launcher)70target_link_libraries (application-info-desktop-test gtest ${GTEST_LIBS} ubuntu-launcher)
6671
67add_test (NAME application-info-desktop-test COMMAND application-info-desktop-test)72add_test (NAME application-info-desktop-test COMMAND application-info-desktop-test)
6873
74# Application Icon Finder
75
76add_executable (application-icon-finder-test
77 # test
78 application-icon-finder.cpp
79
80 #sources
81 ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-icon-finder.cpp)
82target_link_libraries (application-icon-finder-test gtest ${GTEST_LIBS} ubuntu-launcher)
83
84add_test (NAME application-icon-finder-test COMMAND application-icon-finder-test)
85
86file(COPY data DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
87
69# Failure Test88# Failure Test
7089
71add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" )90add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" )
7291
=== added file 'tests/application-icon-finder.cpp'
--- tests/application-icon-finder.cpp 1970-01-01 00:00:00 +0000
+++ tests/application-icon-finder.cpp 2016-05-03 14:23:08 +0000
@@ -0,0 +1,93 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Larry Price <larry.price@canonical.com>
18 */
19
20#include "application-icon-finder.h"
21#include <gtest/gtest.h>
22
23using namespace ubuntu::app_launch;
24
25TEST(ApplicationIconFinder, ReturnsEmptyWhenNoThemeFileAvailable)
26{
27 IconFinder finder("/tmp/please/dont/put/stuff/here");
28 EXPECT_TRUE(finder.find("app").value().empty());
29}
30
31TEST(ApplicationIconFinder, ReturnsEmptyWhenNoAppIconFound)
32{
33 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data";
34 IconFinder finder(basePath);
35 EXPECT_TRUE(finder.find("app_unknown").value().empty());
36}
37
38TEST(ApplicationIconFinder, ReturnsLargestAvailableIcon)
39{
40 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
41 IconFinder finder(basePath);
42 EXPECT_EQ(basePath + "/icons/hicolor/24x24/apps/app.xpm", finder.find("app").value());
43}
44
45TEST(ApplicationIconFinder, ReturnsLargestAvailableIconIncludingLocalIcons)
46{
47 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/home/test/.local/share";
48 IconFinder finder(basePath);
49 EXPECT_EQ(basePath + "/icons/hicolor/32x32/apps/steam_123456.png", finder.find("steam_123456").value());
50}
51
52TEST(ApplicationIconFinder, ReturnsIconAsDirectlyGiven)
53{
54 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
55 IconFinder finder(basePath);
56 EXPECT_EQ(basePath + "/icons/hicolor/scalable/apps/app.svg",
57 finder.find(basePath + "/icons/hicolor/scalable/apps/app.svg").value());
58}
59
60TEST(ApplicationIconFinder, ReturnsIconFromPixmapAsFallback)
61{
62 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
63 IconFinder finder(basePath);
64 EXPECT_EQ(basePath + "/pixmaps/app2.png", finder.find("app2.png").value());
65}
66
67TEST(ApplicationIconFinder, ReturnsIconFromRootThemeDirectory)
68{
69 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
70 IconFinder finder(basePath);
71 EXPECT_EQ(basePath + "/icons/hicolor/app4.png", finder.find("app4.png").value());
72}
73
74TEST(ApplicationIconFinder, ReturnsIconFromRootIconsDirectory)
75{
76 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
77 IconFinder finder(basePath);
78 EXPECT_EQ(basePath + "/icons/app5.png", finder.find("app5.png").value());
79}
80
81TEST(ApplicationIconFinder, ReturnsThresholdIconBasedOnGap)
82{
83 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
84 IconFinder finder(basePath);
85 EXPECT_EQ(basePath + "/icons/hicolor/22x22/apps/app1.png", finder.find("app1.png").value());
86}
87
88TEST(ApplicationIconFinder, IgnoresDirectoriesWithJunkSize)
89{
90 auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share";
91 IconFinder finder(basePath);
92 EXPECT_EQ(basePath + "/icons/hicolor/16x16/apps/app3.png", finder.find("app3.png").value());
93}
094
=== added directory 'tests/data'
=== added directory 'tests/data/home'
=== added directory 'tests/data/home/test'
=== added directory 'tests/data/home/test/.local'
=== added directory 'tests/data/home/test/.local/share'
=== added directory 'tests/data/home/test/.local/share/icons'
=== added directory 'tests/data/home/test/.local/share/icons/hicolor'
=== added directory 'tests/data/home/test/.local/share/icons/hicolor/32x32'
=== added directory 'tests/data/home/test/.local/share/icons/hicolor/32x32/apps'
=== added file 'tests/data/home/test/.local/share/icons/hicolor/32x32/apps/steam_123456.png'
=== added directory 'tests/data/usr'
=== added directory 'tests/data/usr/share'
=== added directory 'tests/data/usr/share/icons'
=== added file 'tests/data/usr/share/icons/app5.png'
=== added directory 'tests/data/usr/share/icons/hicolor'
=== added directory 'tests/data/usr/share/icons/hicolor/16x16'
=== added directory 'tests/data/usr/share/icons/hicolor/16x16/actions'
=== added file 'tests/data/usr/share/icons/hicolor/16x16/actions/app.png'
=== added directory 'tests/data/usr/share/icons/hicolor/16x16/apps'
=== added file 'tests/data/usr/share/icons/hicolor/16x16/apps/app.png'
=== added file 'tests/data/usr/share/icons/hicolor/16x16/apps/app3.png'
=== added file 'tests/data/usr/share/icons/hicolor/16x16/apps/steam_123456.png'
=== added directory 'tests/data/usr/share/icons/hicolor/20x20'
=== added directory 'tests/data/usr/share/icons/hicolor/20x20/apps'
=== added file 'tests/data/usr/share/icons/hicolor/20x20/apps/app3.png'
=== added directory 'tests/data/usr/share/icons/hicolor/22x22'
=== added directory 'tests/data/usr/share/icons/hicolor/22x22/apps'
=== added file 'tests/data/usr/share/icons/hicolor/22x22/apps/app1.png'
=== added directory 'tests/data/usr/share/icons/hicolor/23x23'
=== added directory 'tests/data/usr/share/icons/hicolor/23x23/apps'
=== added directory 'tests/data/usr/share/icons/hicolor/24x24'
=== added directory 'tests/data/usr/share/icons/hicolor/24x24/apps'
=== added file 'tests/data/usr/share/icons/hicolor/24x24/apps/app.xpm'
=== added directory 'tests/data/usr/share/icons/hicolor/25x25'
=== added directory 'tests/data/usr/share/icons/hicolor/25x25/apps'
=== added file 'tests/data/usr/share/icons/hicolor/25x25/apps/app.png'
=== added directory 'tests/data/usr/share/icons/hicolor/32x32'
=== added directory 'tests/data/usr/share/icons/hicolor/32x32/apps'
=== added file 'tests/data/usr/share/icons/hicolor/32x32/apps/app1.png'
=== added file 'tests/data/usr/share/icons/hicolor/app4.png'
=== added file 'tests/data/usr/share/icons/hicolor/index.theme'
--- tests/data/usr/share/icons/hicolor/index.theme 1970-01-01 00:00:00 +0000
+++ tests/data/usr/share/icons/hicolor/index.theme 2016-05-03 14:23:08 +0000
@@ -0,0 +1,48 @@
1[Icon Theme]
2Directories=16x16/actions,16x16/apps,16x16/stock,20x20/apps,22x22/apps,23x23/apps,scalable/apps,24x24/apps,25x25/apps,32x32/apps
3
4[16x16/actions]
5Size=16
6Context=Actions
7Type=Threshold
8
9[16x16/apps]
10Size=16
11Context=Applications
12Type=Threshold
13
14[20x20/apps]
15Size=junk
16Context=Applications
17Type=Fixed
18
19[22x22/apps]
20Size=22
21Threshold=10
22Type=Threshold
23Context=Applications
24
25[23x23/apps]
26MaxSize=junk
27Context=Applications
28Type=scalable
29
30[scalable/apps]
31MaxSize=24
32Context=Applications
33Type=Scalable
34
35[24x24/apps]
36Size=24
37Context=Applications
38Type=Threshold
39
40[25x25/apps]
41Size=25
42Context=Applications
43Type=Fixed
44
45[32x32/apps]
46Size=32
47Context=Applications
48Type=Fixed
049
=== added directory 'tests/data/usr/share/icons/hicolor/scalable'
=== added directory 'tests/data/usr/share/icons/hicolor/scalable/apps'
=== added file 'tests/data/usr/share/icons/hicolor/scalable/apps/app.svg'
=== added directory 'tests/data/usr/share/pixmaps'
=== added file 'tests/data/usr/share/pixmaps/app2.png'

Subscribers

People subscribed via source and target branches