Merge lp:~larryprice/ubuntu-app-launch/find-theme-icons into lp:ubuntu-app-launch/16.04
- find-theme-icons
- Merge into trunk.16.04
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 |
Related bugs: |
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:/
- 287. By Larry Price
-
Removing commented line
- 288. By Larry Price
-
removing unnecessary env setup in CMakeList
- 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
Ted Gould (ted) : | # |
Preview Diff
1 | === modified file 'docs/index.rst' | |||
2 | --- docs/index.rst 2016-04-20 21:29:37 +0000 | |||
3 | +++ docs/index.rst 2016-05-03 14:23:08 +0000 | |||
4 | @@ -106,6 +106,16 @@ | |||
5 | 106 | :private-members: | 106 | :private-members: |
6 | 107 | :undoc-members: | 107 | :undoc-members: |
7 | 108 | 108 | ||
8 | 109 | Application Icon Finder | ||
9 | 110 | ------------------------ | ||
10 | 111 | |||
11 | 112 | .. doxygenclass:: ubuntu::app_launch::app_info::IconFinder | ||
12 | 113 | :project: libubuntu-app-launch | ||
13 | 114 | :members: | ||
14 | 115 | :protected-members: | ||
15 | 116 | :private-members: | ||
16 | 117 | :undoc-members: | ||
17 | 118 | |||
18 | 109 | Helper Implementation Click | 119 | Helper Implementation Click |
19 | 110 | --------------------------- | 120 | --------------------------- |
20 | 111 | 121 | ||
21 | 112 | 122 | ||
22 | === modified file 'libubuntu-app-launch/CMakeLists.txt' | |||
23 | --- libubuntu-app-launch/CMakeLists.txt 2016-02-09 22:51:12 +0000 | |||
24 | +++ libubuntu-app-launch/CMakeLists.txt 2016-05-03 14:23:08 +0000 | |||
25 | @@ -1,4 +1,3 @@ | |||
26 | 1 | |||
27 | 2 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) | 1 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) |
28 | 3 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) | 2 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
29 | 4 | 3 | ||
30 | @@ -40,9 +39,12 @@ | |||
31 | 40 | registry-impl.cpp | 39 | registry-impl.cpp |
32 | 41 | application-impl-base.cpp | 40 | application-impl-base.cpp |
33 | 42 | application-impl-click.cpp | 41 | application-impl-click.cpp |
34 | 42 | application-impl-legacy.h | ||
35 | 43 | application-impl-legacy.cpp | 43 | application-impl-legacy.cpp |
36 | 44 | application-impl-libertine.h | ||
37 | 44 | application-impl-libertine.cpp | 45 | application-impl-libertine.cpp |
38 | 45 | application-info-desktop.cpp | 46 | application-info-desktop.cpp |
39 | 47 | application-icon-finder.cpp | ||
40 | 46 | helper-impl-click.cpp | 48 | helper-impl-click.cpp |
41 | 47 | glib-thread.cpp | 49 | glib-thread.cpp |
42 | 48 | ) | 50 | ) |
43 | 49 | 51 | ||
44 | === added file 'libubuntu-app-launch/application-icon-finder.cpp' | |||
45 | --- libubuntu-app-launch/application-icon-finder.cpp 1970-01-01 00:00:00 +0000 | |||
46 | +++ libubuntu-app-launch/application-icon-finder.cpp 2016-05-03 14:23:08 +0000 | |||
47 | @@ -0,0 +1,353 @@ | |||
48 | 1 | /* | ||
49 | 2 | * Copyright © 2016 Canonical Ltd. | ||
50 | 3 | * | ||
51 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
52 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
53 | 6 | * by the Free Software Foundation. | ||
54 | 7 | * | ||
55 | 8 | * This program is distributed in the hope that it will be useful, but | ||
56 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
57 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
58 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
59 | 12 | * | ||
60 | 13 | * You should have received a copy of the GNU General Public License along | ||
61 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
62 | 15 | * | ||
63 | 16 | * Authors: | ||
64 | 17 | * Larry Price <larry.price@canonical.com> | ||
65 | 18 | */ | ||
66 | 19 | |||
67 | 20 | #include "application-icon-finder.h" | ||
68 | 21 | #include <regex> | ||
69 | 22 | |||
70 | 23 | namespace ubuntu | ||
71 | 24 | { | ||
72 | 25 | namespace app_launch | ||
73 | 26 | { | ||
74 | 27 | namespace | ||
75 | 28 | { | ||
76 | 29 | constexpr auto ICONS_DIR = "/icons"; | ||
77 | 30 | constexpr auto HICOLOR_THEME_DIR = "/icons/hicolor"; | ||
78 | 31 | constexpr auto HICOLOR_THEME_FILE = "/icons/hicolor/index.theme"; | ||
79 | 32 | constexpr auto APPLICATIONS_TYPE = "Applications"; | ||
80 | 33 | constexpr auto SIZE_PROPERTY = "Size"; | ||
81 | 34 | constexpr auto MAXSIZE_PROPERTY = "MaxSize"; | ||
82 | 35 | constexpr auto THRESHOLD_PROPERTY = "Threshold"; | ||
83 | 36 | constexpr auto FIXED_CONTEXT = "Fixed"; | ||
84 | 37 | constexpr auto SCALABLE_CONTEXT = "Scalable"; | ||
85 | 38 | constexpr auto THRESHOLD_CONTEXT = "Threshold"; | ||
86 | 39 | constexpr auto CONTEXT_PROPERTY = "Context"; | ||
87 | 40 | constexpr auto TYPE_PROPERTY = "Type"; | ||
88 | 41 | constexpr auto DIRECTORIES_PROPERTY = "Directories"; | ||
89 | 42 | constexpr auto ICON_THEME_KEY = "Icon Theme"; | ||
90 | 43 | constexpr auto PIXMAPS_PATH = "/pixmaps/"; | ||
91 | 44 | constexpr auto ICON_TYPES = {".png", ".svg", ".xpm"}; | ||
92 | 45 | |||
93 | 46 | static const std::regex iconSizeDirname = std::regex("^(\\d+)x\\1$"); | ||
94 | 47 | } // anonymous namespace | ||
95 | 48 | |||
96 | 49 | IconFinder::IconFinder(std::string basePath) | ||
97 | 50 | : _searchPaths(getSearchPaths(basePath)) | ||
98 | 51 | , _basePath(basePath) | ||
99 | 52 | { | ||
100 | 53 | } | ||
101 | 54 | |||
102 | 55 | /** Finds an icon in the search paths that we have for this path */ | ||
103 | 56 | Application::Info::IconPath IconFinder::find(const std::string& iconName) | ||
104 | 57 | { | ||
105 | 58 | if (iconName[0] == '/') // explicit icon path received | ||
106 | 59 | { | ||
107 | 60 | return Application::Info::IconPath::from_raw(iconName); | ||
108 | 61 | } | ||
109 | 62 | |||
110 | 63 | /* Look in each directory slowly decreasing the size until we find | ||
111 | 64 | an icon */ | ||
112 | 65 | auto size = 0; | ||
113 | 66 | std::string iconPath; | ||
114 | 67 | for (const auto& path : _searchPaths) | ||
115 | 68 | { | ||
116 | 69 | if (path.size > size) | ||
117 | 70 | { | ||
118 | 71 | auto foundIcon = findExistingIcon(path.path, iconName); | ||
119 | 72 | if (!foundIcon.empty()) | ||
120 | 73 | { | ||
121 | 74 | size = path.size; | ||
122 | 75 | iconPath = foundIcon; | ||
123 | 76 | } | ||
124 | 77 | } | ||
125 | 78 | } | ||
126 | 79 | |||
127 | 80 | return Application::Info::IconPath::from_raw(iconPath); | ||
128 | 81 | } | ||
129 | 82 | |||
130 | 83 | /** Check to see if this is an icon name or an icon filename */ | ||
131 | 84 | bool IconFinder::hasImageExtension(const char* filename) | ||
132 | 85 | { | ||
133 | 86 | for (const auto& extension : ICON_TYPES) | ||
134 | 87 | { | ||
135 | 88 | if (g_str_has_suffix(filename, extension)) | ||
136 | 89 | { | ||
137 | 90 | return true; | ||
138 | 91 | } | ||
139 | 92 | } | ||
140 | 93 | return false; | ||
141 | 94 | } | ||
142 | 95 | |||
143 | 96 | /** Check in a given path if there is an existing file in it that satifies our name */ | ||
144 | 97 | std::string IconFinder::findExistingIcon(const std::string& path, const std::string& iconName) | ||
145 | 98 | { | ||
146 | 99 | std::string iconPath; | ||
147 | 100 | |||
148 | 101 | /* If it already has an extension, only check that one */ | ||
149 | 102 | if (hasImageExtension(iconName.c_str())) | ||
150 | 103 | { | ||
151 | 104 | auto fullpath = g_build_filename(path.c_str(), iconName.c_str(), nullptr); | ||
152 | 105 | if (g_file_test(fullpath, G_FILE_TEST_EXISTS)) | ||
153 | 106 | { | ||
154 | 107 | iconPath = fullpath; | ||
155 | 108 | } | ||
156 | 109 | g_free(fullpath); | ||
157 | 110 | return iconPath; | ||
158 | 111 | } | ||
159 | 112 | |||
160 | 113 | /* Otherwise check all the valid extensions to see if they exist */ | ||
161 | 114 | for (const auto& extension : ICON_TYPES) | ||
162 | 115 | { | ||
163 | 116 | auto fullpath = g_build_filename(path.c_str(), (iconName + extension).c_str(), nullptr); | ||
164 | 117 | if (g_file_test(fullpath, G_FILE_TEST_EXISTS)) | ||
165 | 118 | { | ||
166 | 119 | iconPath = fullpath; | ||
167 | 120 | g_free(fullpath); | ||
168 | 121 | break; | ||
169 | 122 | } | ||
170 | 123 | g_free(fullpath); | ||
171 | 124 | } | ||
172 | 125 | return iconPath; | ||
173 | 126 | } | ||
174 | 127 | |||
175 | 128 | /** Create a directory item if the directory exists */ | ||
176 | 129 | std::list<IconFinder::ThemeSubdirectory> IconFinder::validDirectories(const std::string& basePath, | ||
177 | 130 | gchar* directory, | ||
178 | 131 | int size) | ||
179 | 132 | { | ||
180 | 133 | std::list<IconFinder::ThemeSubdirectory> dirs; | ||
181 | 134 | auto globalHicolorTheme = g_build_filename(basePath.c_str(), HICOLOR_THEME_DIR, directory, nullptr); | ||
182 | 135 | if (g_file_test(globalHicolorTheme, G_FILE_TEST_EXISTS)) | ||
183 | 136 | { | ||
184 | 137 | dirs.emplace_back(ThemeSubdirectory{std::string(globalHicolorTheme), size}); | ||
185 | 138 | } | ||
186 | 139 | g_free(globalHicolorTheme); | ||
187 | 140 | |||
188 | 141 | return dirs; | ||
189 | 142 | } | ||
190 | 143 | |||
191 | 144 | /** Take the data in a directory stanza and turn it into an actual directory */ | ||
192 | 145 | std::list<IconFinder::ThemeSubdirectory> IconFinder::addSubdirectoryByType(std::shared_ptr<GKeyFile> themefile, | ||
193 | 146 | gchar* directory, | ||
194 | 147 | const std::string& basePath) | ||
195 | 148 | { | ||
196 | 149 | GError* error = nullptr; | ||
197 | 150 | auto gType = g_key_file_get_string(themefile.get(), directory, TYPE_PROPERTY, &error); | ||
198 | 151 | if (error != nullptr) | ||
199 | 152 | { | ||
200 | 153 | g_error_free(error); | ||
201 | 154 | return std::list<ThemeSubdirectory>{}; | ||
202 | 155 | } | ||
203 | 156 | std::string type(gType); | ||
204 | 157 | g_free(gType); | ||
205 | 158 | |||
206 | 159 | if (type == FIXED_CONTEXT) | ||
207 | 160 | { | ||
208 | 161 | auto size = g_key_file_get_integer(themefile.get(), directory, SIZE_PROPERTY, &error); | ||
209 | 162 | if (error != nullptr) | ||
210 | 163 | { | ||
211 | 164 | g_error_free(error); | ||
212 | 165 | } | ||
213 | 166 | else | ||
214 | 167 | { | ||
215 | 168 | return validDirectories(basePath, directory, size); | ||
216 | 169 | } | ||
217 | 170 | } | ||
218 | 171 | else if (type == SCALABLE_CONTEXT) | ||
219 | 172 | { | ||
220 | 173 | auto size = g_key_file_get_integer(themefile.get(), directory, MAXSIZE_PROPERTY, &error); | ||
221 | 174 | if (error != nullptr) | ||
222 | 175 | { | ||
223 | 176 | g_error_free(error); | ||
224 | 177 | } | ||
225 | 178 | else | ||
226 | 179 | { | ||
227 | 180 | return validDirectories(basePath, directory, size); | ||
228 | 181 | } | ||
229 | 182 | } | ||
230 | 183 | else if (type == THRESHOLD_CONTEXT) | ||
231 | 184 | { | ||
232 | 185 | auto size = g_key_file_get_integer(themefile.get(), directory, SIZE_PROPERTY, &error); | ||
233 | 186 | if (error != nullptr) | ||
234 | 187 | { | ||
235 | 188 | g_error_free(error); | ||
236 | 189 | } | ||
237 | 190 | else | ||
238 | 191 | { | ||
239 | 192 | auto threshold = g_key_file_get_integer(themefile.get(), directory, THRESHOLD_PROPERTY, &error); | ||
240 | 193 | if (error != nullptr) | ||
241 | 194 | { | ||
242 | 195 | threshold = 2; // threshold defaults to 2 | ||
243 | 196 | g_error_free(error); | ||
244 | 197 | } | ||
245 | 198 | return validDirectories(basePath, directory, size + threshold); | ||
246 | 199 | } | ||
247 | 200 | } | ||
248 | 201 | return std::list<ThemeSubdirectory>{}; | ||
249 | 202 | } | ||
250 | 203 | |||
251 | 204 | /** Parse a theme file's various stanzas for each directory */ | ||
252 | 205 | std::list<IconFinder::ThemeSubdirectory> IconFinder::searchIconPaths(std::shared_ptr<GKeyFile> themefile, | ||
253 | 206 | gchar** directories, | ||
254 | 207 | const std::string& basePath) | ||
255 | 208 | { | ||
256 | 209 | std::list<ThemeSubdirectory> subdirs; | ||
257 | 210 | for (auto i = 0; directories[i] != nullptr; ++i) | ||
258 | 211 | { | ||
259 | 212 | GError* error = nullptr; | ||
260 | 213 | auto context = g_key_file_get_string(themefile.get(), directories[i], CONTEXT_PROPERTY, &error); | ||
261 | 214 | if (error != nullptr) | ||
262 | 215 | { | ||
263 | 216 | g_error_free(error); | ||
264 | 217 | continue; | ||
265 | 218 | } | ||
266 | 219 | if (g_strcmp0(context, APPLICATIONS_TYPE) == 0) | ||
267 | 220 | { | ||
268 | 221 | auto newDirs = addSubdirectoryByType(themefile, directories[i], basePath); | ||
269 | 222 | subdirs.splice(subdirs.end(), newDirs); | ||
270 | 223 | } | ||
271 | 224 | g_free(context); | ||
272 | 225 | } | ||
273 | 226 | return subdirs; | ||
274 | 227 | } | ||
275 | 228 | |||
276 | 229 | /** Try to get theme subdirectories using .theme file in the hicolor theme file | ||
277 | 230 | if it exists */ | ||
278 | 231 | std::list<IconFinder::ThemeSubdirectory> IconFinder::themeFileSearchPaths(const std::string& basePath) | ||
279 | 232 | { | ||
280 | 233 | std::string themeFilePath = basePath + HICOLOR_THEME_FILE; | ||
281 | 234 | GError* error = nullptr; | ||
282 | 235 | auto themefile = std::shared_ptr<GKeyFile>(g_key_file_new(), g_key_file_free); | ||
283 | 236 | g_key_file_load_from_file(themefile.get(), themeFilePath.c_str(), G_KEY_FILE_NONE, &error); | ||
284 | 237 | if (error != nullptr) | ||
285 | 238 | { | ||
286 | 239 | g_debug("Unable to find Hicolor theme file: %s", themeFilePath.c_str()); | ||
287 | 240 | g_error_free(error); | ||
288 | 241 | return std::list<ThemeSubdirectory>(); | ||
289 | 242 | } | ||
290 | 243 | |||
291 | 244 | g_key_file_set_list_separator(themefile.get(), ','); | ||
292 | 245 | auto directories = | ||
293 | 246 | g_key_file_get_string_list(themefile.get(), ICON_THEME_KEY, DIRECTORIES_PROPERTY, nullptr, &error); | ||
294 | 247 | if (error != nullptr) | ||
295 | 248 | { | ||
296 | 249 | g_debug("Hicolor theme file '%s' didn't have any directories", themeFilePath.c_str()); | ||
297 | 250 | g_error_free(error); | ||
298 | 251 | return std::list<ThemeSubdirectory>(); | ||
299 | 252 | } | ||
300 | 253 | |||
301 | 254 | auto iconPaths = searchIconPaths(themefile, directories, basePath); | ||
302 | 255 | g_strfreev(directories); | ||
303 | 256 | return iconPaths; | ||
304 | 257 | } | ||
305 | 258 | |||
306 | 259 | /** Look into a theme directory and see if we can use the subdirectories | ||
307 | 260 | as icon folders. Sadly inefficient. */ | ||
308 | 261 | std::list<IconFinder::ThemeSubdirectory> IconFinder::themeDirSearchPaths(const std::string& themeDir) | ||
309 | 262 | { | ||
310 | 263 | std::list<IconFinder::ThemeSubdirectory> searchPaths; | ||
311 | 264 | GError* error = nullptr; | ||
312 | 265 | auto gdir = g_dir_open(themeDir.c_str(), 0, &error); | ||
313 | 266 | |||
314 | 267 | if (error != nullptr) | ||
315 | 268 | { | ||
316 | 269 | g_debug("Unable to open directory '%s' becuase: %s", themeDir.c_str(), error->message); | ||
317 | 270 | g_error_free(error); | ||
318 | 271 | return searchPaths; | ||
319 | 272 | } | ||
320 | 273 | |||
321 | 274 | const gchar* dirname = nullptr; | ||
322 | 275 | while ((dirname = g_dir_read_name(gdir)) != nullptr) | ||
323 | 276 | { | ||
324 | 277 | auto fullPath = g_build_filename(themeDir.c_str(), dirname, "apps", nullptr); | ||
325 | 278 | /* Directories only */ | ||
326 | 279 | if (g_file_test(fullPath, G_FILE_TEST_IS_DIR)) | ||
327 | 280 | { | ||
328 | 281 | if (g_strcmp0(dirname, "scalable") == 0) | ||
329 | 282 | { | ||
330 | 283 | /* We don't really know what to do with scalable here, let's | ||
331 | 284 | call them 256 images */ | ||
332 | 285 | searchPaths.emplace_back(IconFinder::ThemeSubdirectory{fullPath, 256}); | ||
333 | 286 | continue; | ||
334 | 287 | } | ||
335 | 288 | |||
336 | 289 | std::smatch match; | ||
337 | 290 | std::string dirstr(dirname); | ||
338 | 291 | /* We want it to match and have the same values for the first and second size */ | ||
339 | 292 | if (std::regex_match(dirstr, match, iconSizeDirname)) | ||
340 | 293 | { | ||
341 | 294 | searchPaths.emplace_back(IconFinder::ThemeSubdirectory{fullPath, std::atoi(match[1].str().c_str())}); | ||
342 | 295 | } | ||
343 | 296 | } | ||
344 | 297 | g_free(fullPath); | ||
345 | 298 | } | ||
346 | 299 | |||
347 | 300 | g_dir_close(gdir); | ||
348 | 301 | return searchPaths; | ||
349 | 302 | } | ||
350 | 303 | |||
351 | 304 | /** Gets all the search paths, from either a theme file or just | ||
352 | 305 | looking at the directory. And possibly pixmaps as well */ | ||
353 | 306 | std::list<IconFinder::ThemeSubdirectory> IconFinder::getSearchPaths(const std::string& basePath) | ||
354 | 307 | { | ||
355 | 308 | std::list<IconFinder::ThemeSubdirectory> iconPaths; | ||
356 | 309 | |||
357 | 310 | auto hicolorDir = g_build_filename(basePath.c_str(), HICOLOR_THEME_DIR, nullptr); | ||
358 | 311 | if (g_file_test(hicolorDir, G_FILE_TEST_IS_DIR)) | ||
359 | 312 | { | ||
360 | 313 | /* If the directory exists, it could have icons of unknown size */ | ||
361 | 314 | iconPaths.emplace_back(IconFinder::ThemeSubdirectory{hicolorDir, 1}); | ||
362 | 315 | |||
363 | 316 | /* Now see if we can get directories from a theme file */ | ||
364 | 317 | auto themeDirs = themeFileSearchPaths(basePath); | ||
365 | 318 | if (themeDirs.size() > 0) | ||
366 | 319 | { | ||
367 | 320 | iconPaths.splice(iconPaths.end(), themeDirs); | ||
368 | 321 | } | ||
369 | 322 | else | ||
370 | 323 | { | ||
371 | 324 | /* If we didn't get from a theme file, we need to manually scan the directories */ | ||
372 | 325 | auto dirPaths = themeDirSearchPaths(hicolorDir); | ||
373 | 326 | iconPaths.splice(iconPaths.end(), dirPaths); | ||
374 | 327 | } | ||
375 | 328 | } | ||
376 | 329 | g_free(hicolorDir); | ||
377 | 330 | |||
378 | 331 | /* Add root icons directory as potential path */ | ||
379 | 332 | auto iconsPath = g_build_filename(basePath.c_str(), ICONS_DIR, nullptr); | ||
380 | 333 | if (g_file_test(iconsPath, G_FILE_TEST_IS_DIR)) | ||
381 | 334 | { | ||
382 | 335 | iconPaths.emplace_back(IconFinder::ThemeSubdirectory{iconsPath, 1}); | ||
383 | 336 | } | ||
384 | 337 | g_free(iconsPath); | ||
385 | 338 | |||
386 | 339 | /* Add the pixmaps path as a fallback if it exists */ | ||
387 | 340 | auto pixmapsPath = g_build_filename(basePath.c_str(), PIXMAPS_PATH, nullptr); | ||
388 | 341 | if (g_file_test(pixmapsPath, G_FILE_TEST_IS_DIR)) | ||
389 | 342 | { | ||
390 | 343 | iconPaths.emplace_back(IconFinder::ThemeSubdirectory{pixmapsPath, 1}); | ||
391 | 344 | } | ||
392 | 345 | g_free(pixmapsPath); | ||
393 | 346 | |||
394 | 347 | // find icons sorted by size, highest to lowest | ||
395 | 348 | iconPaths.sort([](const ThemeSubdirectory& lhs, const ThemeSubdirectory& rhs) { return lhs.size > rhs.size; }); | ||
396 | 349 | return iconPaths; | ||
397 | 350 | } | ||
398 | 351 | |||
399 | 352 | } // namesapce app_launch | ||
400 | 353 | } // namespace ubuntu | ||
401 | 0 | 354 | ||
402 | === added file 'libubuntu-app-launch/application-icon-finder.h' | |||
403 | --- libubuntu-app-launch/application-icon-finder.h 1970-01-01 00:00:00 +0000 | |||
404 | +++ libubuntu-app-launch/application-icon-finder.h 2016-05-03 14:23:08 +0000 | |||
405 | @@ -0,0 +1,89 @@ | |||
406 | 1 | /* | ||
407 | 2 | * Copyright © 2016 Canonical Ltd. | ||
408 | 3 | * | ||
409 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
410 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
411 | 6 | * by the Free Software Foundation. | ||
412 | 7 | * | ||
413 | 8 | * This program is distributed in the hope that it will be useful, but | ||
414 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
415 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
416 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
417 | 12 | * | ||
418 | 13 | * You should have received a copy of the GNU General Public License along | ||
419 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
420 | 15 | * | ||
421 | 16 | * Authors: | ||
422 | 17 | * Larry Price <larry.price@canonical.com> | ||
423 | 18 | */ | ||
424 | 19 | |||
425 | 20 | #pragma once | ||
426 | 21 | |||
427 | 22 | #include "application-info-desktop.h" | ||
428 | 23 | #include <glib.h> | ||
429 | 24 | #include <list> | ||
430 | 25 | #include <map> | ||
431 | 26 | #include <memory> | ||
432 | 27 | |||
433 | 28 | namespace ubuntu | ||
434 | 29 | { | ||
435 | 30 | namespace app_launch | ||
436 | 31 | { | ||
437 | 32 | /** \brief Class to search for available application icons and select the best option. | ||
438 | 33 | |||
439 | 34 | This object attempts to find the highest resolution icon based on the freedesktop icon | ||
440 | 35 | theme specification found at: | ||
441 | 36 | https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html | ||
442 | 37 | It parses the theme file for the hicolor theme and identifies all possible directories | ||
443 | 38 | in the global scope and the local scope. | ||
444 | 39 | */ | ||
445 | 40 | class IconFinder | ||
446 | 41 | { | ||
447 | 42 | public: | ||
448 | 43 | /** Create an IconFinder | ||
449 | 44 | |||
450 | 45 | \param basePath the root directory to begin searching for themes | ||
451 | 46 | */ | ||
452 | 47 | explicit IconFinder(std::string basePath); | ||
453 | 48 | virtual ~IconFinder() = default; | ||
454 | 49 | |||
455 | 50 | /** Find the optimal icon for the given icon name. | ||
456 | 51 | |||
457 | 52 | \param iconName name of or path to application icon | ||
458 | 53 | */ | ||
459 | 54 | virtual Application::Info::IconPath find(const std::string& iconName); | ||
460 | 55 | |||
461 | 56 | private: | ||
462 | 57 | /** \private */ | ||
463 | 58 | struct ThemeSubdirectory | ||
464 | 59 | { | ||
465 | 60 | std::string path; | ||
466 | 61 | int size; | ||
467 | 62 | }; | ||
468 | 63 | |||
469 | 64 | /** \private */ | ||
470 | 65 | std::list<ThemeSubdirectory> _searchPaths; | ||
471 | 66 | /** \private */ | ||
472 | 67 | std::string _basePath; | ||
473 | 68 | |||
474 | 69 | /** \private */ | ||
475 | 70 | static bool hasImageExtension(const char* filename); | ||
476 | 71 | /** \private */ | ||
477 | 72 | static std::string findExistingIcon(const std::string& path, const std::string& iconName); | ||
478 | 73 | /** \private */ | ||
479 | 74 | static std::list<ThemeSubdirectory> validDirectories(const std::string& basePath, gchar* directory, int size); | ||
480 | 75 | /** \private */ | ||
481 | 76 | static std::list<ThemeSubdirectory> addSubdirectoryByType(std::shared_ptr<GKeyFile> themefile, | ||
482 | 77 | gchar* directory, | ||
483 | 78 | const std::string& basePath); | ||
484 | 79 | /** \private */ | ||
485 | 80 | static std::list<ThemeSubdirectory> searchIconPaths(std::shared_ptr<GKeyFile> themefile, | ||
486 | 81 | gchar** directories, | ||
487 | 82 | const std::string& basePath); | ||
488 | 83 | static std::list<ThemeSubdirectory> themeFileSearchPaths(const std::string& basePath); | ||
489 | 84 | static std::list<ThemeSubdirectory> themeDirSearchPaths(const std::string& basePath); | ||
490 | 85 | static std::list<ThemeSubdirectory> getSearchPaths(const std::string& basePath); | ||
491 | 86 | }; | ||
492 | 87 | |||
493 | 88 | } // namespace app_launch | ||
494 | 89 | } // namesapce ubuntu | ||
495 | 0 | 90 | ||
496 | === modified file 'libubuntu-app-launch/application-impl-legacy.cpp' | |||
497 | --- libubuntu-app-launch/application-impl-legacy.cpp 2016-03-03 20:48:24 +0000 | |||
498 | +++ libubuntu-app-launch/application-impl-legacy.cpp 2016-05-03 14:23:08 +0000 | |||
499 | @@ -27,7 +27,7 @@ | |||
500 | 27 | namespace app_impls | 27 | namespace app_impls |
501 | 28 | { | 28 | { |
502 | 29 | 29 | ||
504 | 30 | std::shared_ptr<GKeyFile> keyfileForApp(const AppID::AppName& name); | 30 | std::pair<std::string, std::shared_ptr<GKeyFile>> keyfileForApp(const AppID::AppName& name); |
505 | 31 | 31 | ||
506 | 32 | void clear_keyfile(GKeyFile* keyfile) | 32 | void clear_keyfile(GKeyFile* keyfile) |
507 | 33 | { | 33 | { |
508 | @@ -38,10 +38,12 @@ | |||
509 | 38 | } | 38 | } |
510 | 39 | 39 | ||
511 | 40 | Legacy::Legacy(const AppID::AppName& appname, | 40 | Legacy::Legacy(const AppID::AppName& appname, |
512 | 41 | const std::string& basedir, | ||
513 | 41 | const std::shared_ptr<GKeyFile>& keyfile, | 42 | const std::shared_ptr<GKeyFile>& keyfile, |
514 | 42 | const std::shared_ptr<Registry>& registry) | 43 | const std::shared_ptr<Registry>& registry) |
515 | 43 | : Base(registry) | 44 | : Base(registry) |
516 | 44 | , _appname(appname) | 45 | , _appname(appname) |
517 | 46 | , _basedir(basedir) | ||
518 | 45 | , _keyfile(keyfile) | 47 | , _keyfile(keyfile) |
519 | 46 | { | 48 | { |
520 | 47 | if (!_keyfile) | 49 | if (!_keyfile) |
521 | @@ -49,15 +51,20 @@ | |||
522 | 49 | } | 51 | } |
523 | 50 | 52 | ||
524 | 51 | Legacy::Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry) | 53 | Legacy::Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry) |
526 | 52 | : Legacy(appname, keyfileForApp(appname), registry) | 54 | : Base(registry) |
527 | 55 | , _appname(appname) | ||
528 | 53 | { | 56 | { |
529 | 57 | std::tie(_basedir, _keyfile) = keyfileForApp(appname); | ||
530 | 58 | |||
531 | 59 | if (!_keyfile) | ||
532 | 60 | throw std::runtime_error{"Unable to find keyfile for legacy application: " + appname.value()}; | ||
533 | 54 | } | 61 | } |
534 | 55 | 62 | ||
536 | 56 | std::shared_ptr<GKeyFile> keyfileForApp(const AppID::AppName& name) | 63 | std::pair<std::string, std::shared_ptr<GKeyFile>> keyfileForApp(const AppID::AppName& name) |
537 | 57 | { | 64 | { |
538 | 58 | std::string desktopName = name.value() + ".desktop"; | 65 | std::string desktopName = name.value() + ".desktop"; |
541 | 59 | auto keyfilecheck = [desktopName](const gchar* dir) -> std::shared_ptr<GKeyFile> { | 66 | auto keyfilecheck = [desktopName](const std::string& dir) -> std::shared_ptr<GKeyFile> { |
542 | 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); |
543 | 61 | if (!g_file_test(fullname, G_FILE_TEST_EXISTS)) | 68 | if (!g_file_test(fullname, G_FILE_TEST_EXISTS)) |
544 | 62 | { | 69 | { |
545 | 63 | g_free(fullname); | 70 | g_free(fullname); |
546 | @@ -80,20 +87,22 @@ | |||
547 | 80 | return keyfile; | 87 | return keyfile; |
548 | 81 | }; | 88 | }; |
549 | 82 | 89 | ||
551 | 83 | auto retval = keyfilecheck(g_get_user_data_dir()); | 90 | std::string basedir = g_get_user_data_dir(); |
552 | 91 | auto retval = keyfilecheck(basedir); | ||
553 | 84 | 92 | ||
554 | 85 | auto systemDirs = g_get_system_data_dirs(); | 93 | auto systemDirs = g_get_system_data_dirs(); |
555 | 86 | for (auto i = 0; !retval && systemDirs[i] != nullptr; i++) | 94 | for (auto i = 0; !retval && systemDirs[i] != nullptr; i++) |
556 | 87 | { | 95 | { |
558 | 88 | retval = keyfilecheck(systemDirs[i]); | 96 | basedir = systemDirs[i]; |
559 | 97 | retval = keyfilecheck(basedir); | ||
560 | 89 | } | 98 | } |
561 | 90 | 99 | ||
563 | 91 | return retval; | 100 | return std::make_pair(basedir, retval); |
564 | 92 | } | 101 | } |
565 | 93 | 102 | ||
566 | 94 | std::shared_ptr<Application::Info> Legacy::info() | 103 | std::shared_ptr<Application::Info> Legacy::info() |
567 | 95 | { | 104 | { |
569 | 96 | return std::make_shared<app_info::Desktop>(_keyfile, "/usr/share/icons/"); | 105 | return std::make_shared<app_info::Desktop>(_keyfile, _basedir, _registry, true); |
570 | 97 | } | 106 | } |
571 | 98 | 107 | ||
572 | 99 | std::list<std::shared_ptr<Application>> Legacy::list(const std::shared_ptr<Registry>& registry) | 108 | std::list<std::shared_ptr<Application>> Legacy::list(const std::shared_ptr<Registry>& registry) |
573 | 100 | 109 | ||
574 | === modified file 'libubuntu-app-launch/application-impl-legacy.h' | |||
575 | --- libubuntu-app-launch/application-impl-legacy.h 2016-02-10 15:27:10 +0000 | |||
576 | +++ libubuntu-app-launch/application-impl-legacy.h 2016-05-03 14:23:08 +0000 | |||
577 | @@ -35,6 +35,7 @@ | |||
578 | 35 | public: | 35 | public: |
579 | 36 | Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry); | 36 | Legacy(const AppID::AppName& appname, const std::shared_ptr<Registry>& registry); |
580 | 37 | Legacy(const AppID::AppName& appname, | 37 | Legacy(const AppID::AppName& appname, |
581 | 38 | const std::string& basedir, | ||
582 | 38 | const std::shared_ptr<GKeyFile>& keyfile, | 39 | const std::shared_ptr<GKeyFile>& keyfile, |
583 | 39 | const std::shared_ptr<Registry>& registry); | 40 | const std::shared_ptr<Registry>& registry); |
584 | 40 | 41 | ||
585 | @@ -45,10 +46,11 @@ | |||
586 | 45 | 46 | ||
587 | 46 | std::shared_ptr<Info> info() override; | 47 | std::shared_ptr<Info> info() override; |
588 | 47 | 48 | ||
590 | 48 | static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry> ®istry); | 49 | static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry); |
591 | 49 | 50 | ||
592 | 50 | private: | 51 | private: |
593 | 51 | AppID::AppName _appname; | 52 | AppID::AppName _appname; |
594 | 53 | std::string _basedir; | ||
595 | 52 | std::shared_ptr<GKeyFile> _keyfile; | 54 | std::shared_ptr<GKeyFile> _keyfile; |
596 | 53 | }; | 55 | }; |
597 | 54 | 56 | ||
598 | 55 | 57 | ||
599 | === modified file 'libubuntu-app-launch/application-impl-libertine.cpp' | |||
600 | --- libubuntu-app-launch/application-impl-libertine.cpp 2016-03-03 20:48:24 +0000 | |||
601 | +++ libubuntu-app-launch/application-impl-libertine.cpp 2016-05-03 14:23:08 +0000 | |||
602 | @@ -41,10 +41,17 @@ | |||
603 | 41 | { | 41 | { |
604 | 42 | auto container_path = libertine_container_path(container.value().c_str()); | 42 | auto container_path = libertine_container_path(container.value().c_str()); |
605 | 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", |
607 | 44 | (appname.value() + ".desktop").c_str(), NULL); | 44 | (appname.value() + ".desktop").c_str(), nullptr); |
608 | 45 | 45 | ||
609 | 46 | _keyfile = keyfileFromPath(container_app_path); | 46 | _keyfile = keyfileFromPath(container_app_path); |
610 | 47 | 47 | ||
611 | 48 | if (_keyfile) | ||
612 | 49 | { | ||
613 | 50 | auto gbasedir = g_build_filename(container_path, "usr", "share", nullptr); | ||
614 | 51 | _basedir = gbasedir; | ||
615 | 52 | g_free(gbasedir); | ||
616 | 53 | } | ||
617 | 54 | |||
618 | 48 | g_free(container_app_path); | 55 | g_free(container_app_path); |
619 | 49 | g_free(container_path); | 56 | g_free(container_path); |
620 | 50 | } | 57 | } |
621 | @@ -57,6 +64,13 @@ | |||
622 | 57 | 64 | ||
623 | 58 | _keyfile = keyfileFromPath(home_app_path); | 65 | _keyfile = keyfileFromPath(home_app_path); |
624 | 59 | 66 | ||
625 | 67 | if (_keyfile) | ||
626 | 68 | { | ||
627 | 69 | auto gbasedir = g_build_filename(home_path, ".local", "share", nullptr); | ||
628 | 70 | _basedir = gbasedir; | ||
629 | 71 | g_free(gbasedir); | ||
630 | 72 | } | ||
631 | 73 | |||
632 | 60 | g_free(home_app_path); | 74 | g_free(home_app_path); |
633 | 61 | g_free(home_path); | 75 | g_free(home_path); |
634 | 62 | } | 76 | } |
635 | @@ -119,7 +133,7 @@ | |||
636 | 119 | 133 | ||
637 | 120 | std::shared_ptr<Application::Info> Libertine::info() | 134 | std::shared_ptr<Application::Info> Libertine::info() |
638 | 121 | { | 135 | { |
640 | 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); |
641 | 123 | } | 137 | } |
642 | 124 | 138 | ||
643 | 125 | }; // namespace app_impls | 139 | }; // namespace app_impls |
644 | 126 | 140 | ||
645 | === modified file 'libubuntu-app-launch/application-impl-libertine.h' | |||
646 | --- libubuntu-app-launch/application-impl-libertine.h 2016-02-10 15:38:21 +0000 | |||
647 | +++ libubuntu-app-launch/application-impl-libertine.h 2016-05-03 14:23:08 +0000 | |||
648 | @@ -36,7 +36,7 @@ | |||
649 | 36 | const AppID::AppName& appname, | 36 | const AppID::AppName& appname, |
650 | 37 | const std::shared_ptr<Registry>& registry); | 37 | const std::shared_ptr<Registry>& registry); |
651 | 38 | 38 | ||
653 | 39 | static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry> ®istry); | 39 | static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry); |
654 | 40 | 40 | ||
655 | 41 | AppID appId() override | 41 | AppID appId() override |
656 | 42 | { | 42 | { |
657 | @@ -49,6 +49,7 @@ | |||
658 | 49 | AppID::Package _container; | 49 | AppID::Package _container; |
659 | 50 | AppID::AppName _appname; | 50 | AppID::AppName _appname; |
660 | 51 | std::shared_ptr<GKeyFile> _keyfile; | 51 | std::shared_ptr<GKeyFile> _keyfile; |
661 | 52 | std::string _basedir; | ||
662 | 52 | }; | 53 | }; |
663 | 53 | 54 | ||
664 | 54 | }; // namespace app_impls | 55 | }; // namespace app_impls |
665 | 55 | 56 | ||
666 | === modified file 'libubuntu-app-launch/application-info-desktop.cpp' | |||
667 | --- libubuntu-app-launch/application-info-desktop.cpp 2016-05-03 14:23:08 +0000 | |||
668 | +++ libubuntu-app-launch/application-info-desktop.cpp 2016-05-03 14:23:08 +0000 | |||
669 | @@ -18,6 +18,8 @@ | |||
670 | 18 | */ | 18 | */ |
671 | 19 | 19 | ||
672 | 20 | #include "application-info-desktop.h" | 20 | #include "application-info-desktop.h" |
673 | 21 | #include "application-icon-finder.h" | ||
674 | 22 | #include "registry-impl.h" | ||
675 | 21 | #include <cstdlib> | 23 | #include <cstdlib> |
676 | 22 | 24 | ||
677 | 23 | namespace ubuntu | 25 | namespace ubuntu |
678 | @@ -38,7 +40,7 @@ | |||
679 | 38 | 40 | ||
680 | 39 | struct NoDisplayTag; | 41 | struct NoDisplayTag; |
681 | 40 | typedef TypeTagger<NoDisplayTag, bool> NoDisplay; | 42 | typedef TypeTagger<NoDisplayTag, bool> NoDisplay; |
683 | 41 | } // anonymous namespace | 43 | } // anonymous namespace |
684 | 42 | 44 | ||
685 | 43 | template <typename T> | 45 | template <typename T> |
686 | 44 | auto stringFromKeyfile(std::shared_ptr<GKeyFile> keyfile, const std::string& key, const std::string& exceptionText = {}) | 46 | auto stringFromKeyfile(std::shared_ptr<GKeyFile> keyfile, const std::string& key, const std::string& exceptionText = {}) |
687 | @@ -134,8 +136,8 @@ | |||
688 | 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); |
689 | 135 | if (error != nullptr) | 137 | if (error != nullptr) |
690 | 136 | { | 138 | { |
693 | 137 | g_error_free(error); | 139 | g_error_free(error); |
694 | 138 | return defaultValue; | 140 | return defaultValue; |
695 | 139 | } | 141 | } |
696 | 140 | 142 | ||
697 | 141 | bool result = false; | 143 | bool result = false; |
698 | @@ -152,8 +154,11 @@ | |||
699 | 152 | return result; | 154 | return result; |
700 | 153 | } | 155 | } |
701 | 154 | 156 | ||
704 | 155 | Desktop::Desktop(std::shared_ptr<GKeyFile> keyfile, const std::string& basePath) | 157 | Desktop::Desktop(std::shared_ptr<GKeyFile> keyfile, |
705 | 156 | : _keyfile([keyfile]() { | 158 | const std::string& basePath, |
706 | 159 | std::shared_ptr<Registry> registry, | ||
707 | 160 | bool allowNoDisplay) | ||
708 | 161 | : _keyfile([keyfile, allowNoDisplay]() { | ||
709 | 157 | if (!keyfile) | 162 | if (!keyfile) |
710 | 158 | { | 163 | { |
711 | 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"); |
712 | @@ -162,7 +167,7 @@ | |||
713 | 162 | { | 167 | { |
714 | 163 | throw std::runtime_error("Keyfile does not represent application type"); | 168 | throw std::runtime_error("Keyfile does not represent application type"); |
715 | 164 | } | 169 | } |
717 | 165 | if (boolFromKeyfile<NoDisplay>(keyfile, "NoDisplay", false).value()) | 170 | if (boolFromKeyfile<NoDisplay>(keyfile, "NoDisplay", false).value() && !allowNoDisplay) |
718 | 166 | { | 171 | { |
719 | 167 | throw std::runtime_error("Application is not meant to be displayed"); | 172 | throw std::runtime_error("Application is not meant to be displayed"); |
720 | 168 | } | 173 | } |
721 | @@ -171,10 +176,13 @@ | |||
722 | 171 | throw std::runtime_error("Application keyfile is hidden"); | 176 | throw std::runtime_error("Application keyfile is hidden"); |
723 | 172 | } | 177 | } |
724 | 173 | auto xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP"); | 178 | auto xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP"); |
727 | 174 | if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) | 179 | if (xdg_current_desktop != nullptr) |
726 | 175 | || !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true)) | ||
728 | 176 | { | 180 | { |
730 | 177 | throw std::runtime_error("Application is not shown in Unity"); | 181 | if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) || |
731 | 182 | !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true)) | ||
732 | 183 | { | ||
733 | 184 | throw std::runtime_error("Application is not shown in Unity"); | ||
734 | 185 | } | ||
735 | 178 | } | 186 | } |
736 | 179 | 187 | ||
737 | 180 | return keyfile; | 188 | return keyfile; |
738 | @@ -182,8 +190,15 @@ | |||
739 | 182 | , _basePath(basePath) | 190 | , _basePath(basePath) |
740 | 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")) |
741 | 184 | , _description(stringFromKeyfile<Application::Info::Description>(keyfile, "Comment")) | 192 | , _description(stringFromKeyfile<Application::Info::Description>(keyfile, "Comment")) |
744 | 185 | , _iconPath( | 193 | , _iconPath([keyfile, basePath, registry]() { |
745 | 186 | fileFromKeyfile<Application::Info::IconPath>(keyfile, basePath, "Icon", "Missing icon for desktop file")) | 194 | if (registry != nullptr) |
746 | 195 | { | ||
747 | 196 | auto iconName = | ||
748 | 197 | stringFromKeyfile<Application::Info::IconPath>(keyfile, "Icon", "Missing icon for desktop file"); | ||
749 | 198 | return registry->impl->getIconFinder(basePath)->find(iconName); | ||
750 | 199 | } | ||
751 | 200 | return fileFromKeyfile<Application::Info::IconPath>(keyfile, basePath, "Icon", "Missing icon for desktop file"); | ||
752 | 201 | }()) | ||
753 | 187 | , _splashInfo({ | 202 | , _splashInfo({ |
754 | 188 | title : stringFromKeyfile<Application::Info::Splash::Title>(keyfile, "X-Ubuntu-Splash-Title"), | 203 | title : stringFromKeyfile<Application::Info::Splash::Title>(keyfile, "X-Ubuntu-Splash-Title"), |
755 | 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"), |
756 | 190 | 205 | ||
757 | === modified file 'libubuntu-app-launch/application-info-desktop.h' | |||
758 | --- libubuntu-app-launch/application-info-desktop.h 2016-02-10 22:04:00 +0000 | |||
759 | +++ libubuntu-app-launch/application-info-desktop.h 2016-05-03 14:23:08 +0000 | |||
760 | @@ -33,7 +33,10 @@ | |||
761 | 33 | class Desktop : public Application::Info | 33 | class Desktop : public Application::Info |
762 | 34 | { | 34 | { |
763 | 35 | public: | 35 | public: |
765 | 36 | Desktop(std::shared_ptr<GKeyFile> keyfile, const std::string& basePath); | 36 | Desktop(std::shared_ptr<GKeyFile> keyfile, |
766 | 37 | const std::string& basePath, | ||
767 | 38 | std::shared_ptr<Registry> registry = nullptr, | ||
768 | 39 | bool allowNoDisplay = false); | ||
769 | 37 | 40 | ||
770 | 38 | const Application::Info::Name& name() override | 41 | const Application::Info::Name& name() override |
771 | 39 | { | 42 | { |
772 | 40 | 43 | ||
773 | === modified file 'libubuntu-app-launch/application.cpp' | |||
774 | --- libubuntu-app-launch/application.cpp 2016-04-27 14:22:39 +0000 | |||
775 | +++ libubuntu-app-launch/application.cpp 2016-05-03 14:23:08 +0000 | |||
776 | @@ -75,10 +75,8 @@ | |||
777 | 75 | { | 75 | { |
778 | 76 | } | 76 | } |
779 | 77 | 77 | ||
780 | 78 | /* These are the Regex's taken from the Click Reviewer Tools | ||
781 | 79 | on Jan 16, 2016 revision 566 */ | ||
782 | 80 | #define REGEX_PKGNAME "([a-z0-9][a-z0-9+.-]+)" | 78 | #define REGEX_PKGNAME "([a-z0-9][a-z0-9+.-]+)" |
784 | 81 | #define REGEX_APPNAME "([A-Za-z0-9+-.:~-]+)" | 79 | #define REGEX_APPNAME "([A-Za-z0-9+-.:~-][\\sA-Za-z0-9+-.:~-]+)" |
785 | 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+.~]+)?)" |
786 | 83 | 81 | ||
787 | 84 | const std::regex full_appid_regex("^" REGEX_PKGNAME "_" REGEX_APPNAME "_" REGEX_VERSION "$"); | 82 | const std::regex full_appid_regex("^" REGEX_PKGNAME "_" REGEX_APPNAME "_" REGEX_VERSION "$"); |
788 | 85 | 83 | ||
789 | === modified file 'libubuntu-app-launch/application.h' | |||
790 | --- libubuntu-app-launch/application.h 2016-04-19 02:14:03 +0000 | |||
791 | +++ libubuntu-app-launch/application.h 2016-05-03 14:23:08 +0000 | |||
792 | @@ -38,7 +38,7 @@ | |||
793 | 38 | /** \brief Class to represent an application, whether running or not, and | 38 | /** \brief Class to represent an application, whether running or not, and |
794 | 39 | query more information about it. | 39 | query more information about it. |
795 | 40 | 40 | ||
797 | 41 | Generally the Application object represnts an Application in the system. It | 41 | Generally the Application object represents an Application in the system. It |
798 | 42 | hooks up all of it's signals, finds out information about it and controls | 42 | hooks up all of it's signals, finds out information about it and controls |
799 | 43 | whether it is running or not. This class is what most users of Ubuntu App | 43 | whether it is running or not. This class is what most users of Ubuntu App |
800 | 44 | Launch will do the majority of their work. | 44 | Launch will do the majority of their work. |
801 | 45 | 45 | ||
802 | === modified file 'libubuntu-app-launch/registry-impl.cpp' | |||
803 | --- libubuntu-app-launch/registry-impl.cpp 2016-03-03 20:48:24 +0000 | |||
804 | +++ libubuntu-app-launch/registry-impl.cpp 2016-05-03 14:23:08 +0000 | |||
805 | @@ -18,6 +18,7 @@ | |||
806 | 18 | */ | 18 | */ |
807 | 19 | 19 | ||
808 | 20 | #include "registry-impl.h" | 20 | #include "registry-impl.h" |
809 | 21 | #include "application-icon-finder.h" | ||
810 | 21 | 22 | ||
811 | 22 | namespace ubuntu | 23 | namespace ubuntu |
812 | 23 | { | 24 | { |
813 | @@ -34,6 +35,7 @@ | |||
814 | 34 | _dbus.reset(); | 35 | _dbus.reset(); |
815 | 35 | }) | 36 | }) |
816 | 36 | , _registry(registry) | 37 | , _registry(registry) |
817 | 38 | , _iconFinders() | ||
818 | 37 | // _manager(nullptr) | 39 | // _manager(nullptr) |
819 | 38 | { | 40 | { |
820 | 39 | auto cancel = thread.getCancellable(); | 41 | auto cancel = thread.getCancellable(); |
821 | @@ -162,6 +164,15 @@ | |||
822 | 162 | }); | 164 | }); |
823 | 163 | } | 165 | } |
824 | 164 | 166 | ||
825 | 167 | std::shared_ptr<IconFinder> Registry::Impl::getIconFinder(std::string basePath) | ||
826 | 168 | { | ||
827 | 169 | if (_iconFinders.find(basePath) == _iconFinders.end()) | ||
828 | 170 | { | ||
829 | 171 | _iconFinders[basePath] = std::make_shared<IconFinder>(basePath); | ||
830 | 172 | } | ||
831 | 173 | return _iconFinders[basePath]; | ||
832 | 174 | } | ||
833 | 175 | |||
834 | 165 | #if 0 | 176 | #if 0 |
835 | 166 | void | 177 | void |
836 | 167 | Registry::Impl::setManager (Registry::Manager* manager) | 178 | Registry::Impl::setManager (Registry::Manager* manager) |
837 | 168 | 179 | ||
838 | === modified file 'libubuntu-app-launch/registry-impl.h' | |||
839 | --- libubuntu-app-launch/registry-impl.h 2016-04-18 18:29:32 +0000 | |||
840 | +++ libubuntu-app-launch/registry-impl.h 2016-05-03 14:23:08 +0000 | |||
841 | @@ -17,12 +17,12 @@ | |||
842 | 17 | * Ted Gould <ted.gould@canonical.com> | 17 | * Ted Gould <ted.gould@canonical.com> |
843 | 18 | */ | 18 | */ |
844 | 19 | 19 | ||
845 | 20 | #include "glib-thread.h" | ||
846 | 20 | #include "registry.h" | 21 | #include "registry.h" |
847 | 21 | #include "glib-thread.h" | ||
848 | 22 | |||
849 | 23 | #include <json-glib/json-glib.h> | ||
850 | 24 | #include <click.h> | 22 | #include <click.h> |
851 | 25 | #include <gio/gio.h> | 23 | #include <gio/gio.h> |
852 | 24 | #include <json-glib/json-glib.h> | ||
853 | 25 | #include <unordered_map> | ||
854 | 26 | 26 | ||
855 | 27 | #pragma once | 27 | #pragma once |
856 | 28 | 28 | ||
857 | @@ -31,6 +31,8 @@ | |||
858 | 31 | namespace app_launch | 31 | namespace app_launch |
859 | 32 | { | 32 | { |
860 | 33 | 33 | ||
861 | 34 | class IconFinder; | ||
862 | 35 | |||
863 | 34 | /** \private | 36 | /** \private |
864 | 35 | \brief Private implementation of the Registry object | 37 | \brief Private implementation of the Registry object |
865 | 36 | 38 | ||
866 | @@ -55,6 +57,8 @@ | |||
867 | 55 | 57 | ||
868 | 56 | GLib::ContextThread thread; | 58 | GLib::ContextThread thread; |
869 | 57 | 59 | ||
870 | 60 | std::shared_ptr<IconFinder> getIconFinder(std::string basePath); | ||
871 | 61 | |||
872 | 58 | private: | 62 | private: |
873 | 59 | Registry* _registry; | 63 | Registry* _registry; |
874 | 60 | #if 0 | 64 | #if 0 |
875 | @@ -67,6 +71,8 @@ | |||
876 | 67 | std::shared_ptr<GDBusConnection> _dbus; | 71 | std::shared_ptr<GDBusConnection> _dbus; |
877 | 68 | 72 | ||
878 | 69 | void initClick(); | 73 | void initClick(); |
879 | 74 | |||
880 | 75 | std::unordered_map<std::string, std::shared_ptr<IconFinder>> _iconFinders; | ||
881 | 70 | }; | 76 | }; |
882 | 71 | 77 | ||
883 | 72 | }; // namespace app_launch | 78 | }; // namespace app_launch |
884 | 73 | 79 | ||
885 | === modified file 'tests/CMakeLists.txt' | |||
886 | --- tests/CMakeLists.txt 2016-02-17 21:56:34 +0000 | |||
887 | +++ tests/CMakeLists.txt 2016-05-03 14:23:08 +0000 | |||
888 | @@ -1,4 +1,3 @@ | |||
889 | 1 | |||
890 | 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") | 1 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") |
891 | 3 | 2 | ||
892 | 4 | configure_file ("click-db-dir/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-db-dir/test.conf" @ONLY) | 3 | configure_file ("click-db-dir/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-db-dir/test.conf" @ONLY) |
893 | @@ -60,12 +59,32 @@ | |||
894 | 60 | # Application Info Desktop | 59 | # Application Info Desktop |
895 | 61 | 60 | ||
896 | 62 | add_executable (application-info-desktop-test | 61 | add_executable (application-info-desktop-test |
899 | 63 | application-info-desktop.cpp | 62 | # test |
900 | 64 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-info-desktop.cpp) | 63 | application-info-desktop.cpp |
901 | 64 | |||
902 | 65 | # sources | ||
903 | 66 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-info-desktop.cpp | ||
904 | 67 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-icon-finder.cpp | ||
905 | 68 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/glib-thread.cpp | ||
906 | 69 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/registry-impl.cpp) | ||
907 | 65 | target_link_libraries (application-info-desktop-test gtest ${GTEST_LIBS} ubuntu-launcher) | 70 | target_link_libraries (application-info-desktop-test gtest ${GTEST_LIBS} ubuntu-launcher) |
908 | 66 | 71 | ||
909 | 67 | add_test (NAME application-info-desktop-test COMMAND application-info-desktop-test) | 72 | add_test (NAME application-info-desktop-test COMMAND application-info-desktop-test) |
910 | 68 | 73 | ||
911 | 74 | # Application Icon Finder | ||
912 | 75 | |||
913 | 76 | add_executable (application-icon-finder-test | ||
914 | 77 | # test | ||
915 | 78 | application-icon-finder.cpp | ||
916 | 79 | |||
917 | 80 | #sources | ||
918 | 81 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-icon-finder.cpp) | ||
919 | 82 | target_link_libraries (application-icon-finder-test gtest ${GTEST_LIBS} ubuntu-launcher) | ||
920 | 83 | |||
921 | 84 | add_test (NAME application-icon-finder-test COMMAND application-icon-finder-test) | ||
922 | 85 | |||
923 | 86 | file(COPY data DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) | ||
924 | 87 | |||
925 | 69 | # Failure Test | 88 | # Failure Test |
926 | 70 | 89 | ||
927 | 71 | add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" ) | 90 | add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" ) |
928 | 72 | 91 | ||
929 | === added file 'tests/application-icon-finder.cpp' | |||
930 | --- tests/application-icon-finder.cpp 1970-01-01 00:00:00 +0000 | |||
931 | +++ tests/application-icon-finder.cpp 2016-05-03 14:23:08 +0000 | |||
932 | @@ -0,0 +1,93 @@ | |||
933 | 1 | /* | ||
934 | 2 | * Copyright © 2016 Canonical Ltd. | ||
935 | 3 | * | ||
936 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
937 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
938 | 6 | * by the Free Software Foundation. | ||
939 | 7 | * | ||
940 | 8 | * This program is distributed in the hope that it will be useful, but | ||
941 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
942 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
943 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
944 | 12 | * | ||
945 | 13 | * You should have received a copy of the GNU General Public License along | ||
946 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
947 | 15 | * | ||
948 | 16 | * Authors: | ||
949 | 17 | * Larry Price <larry.price@canonical.com> | ||
950 | 18 | */ | ||
951 | 19 | |||
952 | 20 | #include "application-icon-finder.h" | ||
953 | 21 | #include <gtest/gtest.h> | ||
954 | 22 | |||
955 | 23 | using namespace ubuntu::app_launch; | ||
956 | 24 | |||
957 | 25 | TEST(ApplicationIconFinder, ReturnsEmptyWhenNoThemeFileAvailable) | ||
958 | 26 | { | ||
959 | 27 | IconFinder finder("/tmp/please/dont/put/stuff/here"); | ||
960 | 28 | EXPECT_TRUE(finder.find("app").value().empty()); | ||
961 | 29 | } | ||
962 | 30 | |||
963 | 31 | TEST(ApplicationIconFinder, ReturnsEmptyWhenNoAppIconFound) | ||
964 | 32 | { | ||
965 | 33 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data"; | ||
966 | 34 | IconFinder finder(basePath); | ||
967 | 35 | EXPECT_TRUE(finder.find("app_unknown").value().empty()); | ||
968 | 36 | } | ||
969 | 37 | |||
970 | 38 | TEST(ApplicationIconFinder, ReturnsLargestAvailableIcon) | ||
971 | 39 | { | ||
972 | 40 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
973 | 41 | IconFinder finder(basePath); | ||
974 | 42 | EXPECT_EQ(basePath + "/icons/hicolor/24x24/apps/app.xpm", finder.find("app").value()); | ||
975 | 43 | } | ||
976 | 44 | |||
977 | 45 | TEST(ApplicationIconFinder, ReturnsLargestAvailableIconIncludingLocalIcons) | ||
978 | 46 | { | ||
979 | 47 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/home/test/.local/share"; | ||
980 | 48 | IconFinder finder(basePath); | ||
981 | 49 | EXPECT_EQ(basePath + "/icons/hicolor/32x32/apps/steam_123456.png", finder.find("steam_123456").value()); | ||
982 | 50 | } | ||
983 | 51 | |||
984 | 52 | TEST(ApplicationIconFinder, ReturnsIconAsDirectlyGiven) | ||
985 | 53 | { | ||
986 | 54 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
987 | 55 | IconFinder finder(basePath); | ||
988 | 56 | EXPECT_EQ(basePath + "/icons/hicolor/scalable/apps/app.svg", | ||
989 | 57 | finder.find(basePath + "/icons/hicolor/scalable/apps/app.svg").value()); | ||
990 | 58 | } | ||
991 | 59 | |||
992 | 60 | TEST(ApplicationIconFinder, ReturnsIconFromPixmapAsFallback) | ||
993 | 61 | { | ||
994 | 62 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
995 | 63 | IconFinder finder(basePath); | ||
996 | 64 | EXPECT_EQ(basePath + "/pixmaps/app2.png", finder.find("app2.png").value()); | ||
997 | 65 | } | ||
998 | 66 | |||
999 | 67 | TEST(ApplicationIconFinder, ReturnsIconFromRootThemeDirectory) | ||
1000 | 68 | { | ||
1001 | 69 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
1002 | 70 | IconFinder finder(basePath); | ||
1003 | 71 | EXPECT_EQ(basePath + "/icons/hicolor/app4.png", finder.find("app4.png").value()); | ||
1004 | 72 | } | ||
1005 | 73 | |||
1006 | 74 | TEST(ApplicationIconFinder, ReturnsIconFromRootIconsDirectory) | ||
1007 | 75 | { | ||
1008 | 76 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
1009 | 77 | IconFinder finder(basePath); | ||
1010 | 78 | EXPECT_EQ(basePath + "/icons/app5.png", finder.find("app5.png").value()); | ||
1011 | 79 | } | ||
1012 | 80 | |||
1013 | 81 | TEST(ApplicationIconFinder, ReturnsThresholdIconBasedOnGap) | ||
1014 | 82 | { | ||
1015 | 83 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
1016 | 84 | IconFinder finder(basePath); | ||
1017 | 85 | EXPECT_EQ(basePath + "/icons/hicolor/22x22/apps/app1.png", finder.find("app1.png").value()); | ||
1018 | 86 | } | ||
1019 | 87 | |||
1020 | 88 | TEST(ApplicationIconFinder, IgnoresDirectoriesWithJunkSize) | ||
1021 | 89 | { | ||
1022 | 90 | auto basePath = std::string(CMAKE_SOURCE_DIR) + "/data/usr/share"; | ||
1023 | 91 | IconFinder finder(basePath); | ||
1024 | 92 | EXPECT_EQ(basePath + "/icons/hicolor/16x16/apps/app3.png", finder.find("app3.png").value()); | ||
1025 | 93 | } | ||
1026 | 0 | 94 | ||
1027 | === added directory 'tests/data' | |||
1028 | === added directory 'tests/data/home' | |||
1029 | === added directory 'tests/data/home/test' | |||
1030 | === added directory 'tests/data/home/test/.local' | |||
1031 | === added directory 'tests/data/home/test/.local/share' | |||
1032 | === added directory 'tests/data/home/test/.local/share/icons' | |||
1033 | === added directory 'tests/data/home/test/.local/share/icons/hicolor' | |||
1034 | === added directory 'tests/data/home/test/.local/share/icons/hicolor/32x32' | |||
1035 | === added directory 'tests/data/home/test/.local/share/icons/hicolor/32x32/apps' | |||
1036 | === added file 'tests/data/home/test/.local/share/icons/hicolor/32x32/apps/steam_123456.png' | |||
1037 | === added directory 'tests/data/usr' | |||
1038 | === added directory 'tests/data/usr/share' | |||
1039 | === added directory 'tests/data/usr/share/icons' | |||
1040 | === added file 'tests/data/usr/share/icons/app5.png' | |||
1041 | === added directory 'tests/data/usr/share/icons/hicolor' | |||
1042 | === added directory 'tests/data/usr/share/icons/hicolor/16x16' | |||
1043 | === added directory 'tests/data/usr/share/icons/hicolor/16x16/actions' | |||
1044 | === added file 'tests/data/usr/share/icons/hicolor/16x16/actions/app.png' | |||
1045 | === added directory 'tests/data/usr/share/icons/hicolor/16x16/apps' | |||
1046 | === added file 'tests/data/usr/share/icons/hicolor/16x16/apps/app.png' | |||
1047 | === added file 'tests/data/usr/share/icons/hicolor/16x16/apps/app3.png' | |||
1048 | === added file 'tests/data/usr/share/icons/hicolor/16x16/apps/steam_123456.png' | |||
1049 | === added directory 'tests/data/usr/share/icons/hicolor/20x20' | |||
1050 | === added directory 'tests/data/usr/share/icons/hicolor/20x20/apps' | |||
1051 | === added file 'tests/data/usr/share/icons/hicolor/20x20/apps/app3.png' | |||
1052 | === added directory 'tests/data/usr/share/icons/hicolor/22x22' | |||
1053 | === added directory 'tests/data/usr/share/icons/hicolor/22x22/apps' | |||
1054 | === added file 'tests/data/usr/share/icons/hicolor/22x22/apps/app1.png' | |||
1055 | === added directory 'tests/data/usr/share/icons/hicolor/23x23' | |||
1056 | === added directory 'tests/data/usr/share/icons/hicolor/23x23/apps' | |||
1057 | === added directory 'tests/data/usr/share/icons/hicolor/24x24' | |||
1058 | === added directory 'tests/data/usr/share/icons/hicolor/24x24/apps' | |||
1059 | === added file 'tests/data/usr/share/icons/hicolor/24x24/apps/app.xpm' | |||
1060 | === added directory 'tests/data/usr/share/icons/hicolor/25x25' | |||
1061 | === added directory 'tests/data/usr/share/icons/hicolor/25x25/apps' | |||
1062 | === added file 'tests/data/usr/share/icons/hicolor/25x25/apps/app.png' | |||
1063 | === added directory 'tests/data/usr/share/icons/hicolor/32x32' | |||
1064 | === added directory 'tests/data/usr/share/icons/hicolor/32x32/apps' | |||
1065 | === added file 'tests/data/usr/share/icons/hicolor/32x32/apps/app1.png' | |||
1066 | === added file 'tests/data/usr/share/icons/hicolor/app4.png' | |||
1067 | === added file 'tests/data/usr/share/icons/hicolor/index.theme' | |||
1068 | --- tests/data/usr/share/icons/hicolor/index.theme 1970-01-01 00:00:00 +0000 | |||
1069 | +++ tests/data/usr/share/icons/hicolor/index.theme 2016-05-03 14:23:08 +0000 | |||
1070 | @@ -0,0 +1,48 @@ | |||
1071 | 1 | [Icon Theme] | ||
1072 | 2 | Directories=16x16/actions,16x16/apps,16x16/stock,20x20/apps,22x22/apps,23x23/apps,scalable/apps,24x24/apps,25x25/apps,32x32/apps | ||
1073 | 3 | |||
1074 | 4 | [16x16/actions] | ||
1075 | 5 | Size=16 | ||
1076 | 6 | Context=Actions | ||
1077 | 7 | Type=Threshold | ||
1078 | 8 | |||
1079 | 9 | [16x16/apps] | ||
1080 | 10 | Size=16 | ||
1081 | 11 | Context=Applications | ||
1082 | 12 | Type=Threshold | ||
1083 | 13 | |||
1084 | 14 | [20x20/apps] | ||
1085 | 15 | Size=junk | ||
1086 | 16 | Context=Applications | ||
1087 | 17 | Type=Fixed | ||
1088 | 18 | |||
1089 | 19 | [22x22/apps] | ||
1090 | 20 | Size=22 | ||
1091 | 21 | Threshold=10 | ||
1092 | 22 | Type=Threshold | ||
1093 | 23 | Context=Applications | ||
1094 | 24 | |||
1095 | 25 | [23x23/apps] | ||
1096 | 26 | MaxSize=junk | ||
1097 | 27 | Context=Applications | ||
1098 | 28 | Type=scalable | ||
1099 | 29 | |||
1100 | 30 | [scalable/apps] | ||
1101 | 31 | MaxSize=24 | ||
1102 | 32 | Context=Applications | ||
1103 | 33 | Type=Scalable | ||
1104 | 34 | |||
1105 | 35 | [24x24/apps] | ||
1106 | 36 | Size=24 | ||
1107 | 37 | Context=Applications | ||
1108 | 38 | Type=Threshold | ||
1109 | 39 | |||
1110 | 40 | [25x25/apps] | ||
1111 | 41 | Size=25 | ||
1112 | 42 | Context=Applications | ||
1113 | 43 | Type=Fixed | ||
1114 | 44 | |||
1115 | 45 | [32x32/apps] | ||
1116 | 46 | Size=32 | ||
1117 | 47 | Context=Applications | ||
1118 | 48 | Type=Fixed | ||
1119 | 0 | 49 | ||
1120 | === added directory 'tests/data/usr/share/icons/hicolor/scalable' | |||
1121 | === added directory 'tests/data/usr/share/icons/hicolor/scalable/apps' | |||
1122 | === added file 'tests/data/usr/share/icons/hicolor/scalable/apps/app.svg' | |||
1123 | === added directory 'tests/data/usr/share/pixmaps' | |||
1124 | === added file 'tests/data/usr/share/pixmaps/app2.png' |
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)