| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "vm_tools/garcon/icon_finder.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <vector> |
| |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/strings/stringprintf.h> |
| #include <base/strings/string_split.h> |
| #include "vm_tools/garcon/desktop_file.h" |
| #include "vm_tools/garcon/icon_index_file.h" |
| #include "vm_tools/garcon/xdg_util.h" |
| |
| namespace vm_tools { |
| namespace garcon { |
| namespace { |
| |
| constexpr char kDefaultPixmapsDir[] = "/usr/share/pixmaps/"; |
| const char* const kThemeDirs[] = {"gnome", "hicolor"}; |
| const int kDefaultIconSizeDirs[] = {256, 128, 96, 64, 48, 32}; |
| constexpr char kDefaultIconSubdir[] = "apps"; |
| |
| // Returns a vector of directory paths under which an index.theme file is |
| // located. |
| std::vector<base::FilePath> GetPathsForIconIndexDirs() { |
| std::vector<base::FilePath> retval; |
| // Icons are stored in the same place as applications, so just use that list. |
| std::vector<base::FilePath> dirs = xdg::GetDataDirectories(); |
| for (const char* theme_dir : kThemeDirs) { |
| std::transform(dirs.begin(), dirs.end(), std::back_inserter(retval), |
| [&theme_dir](const base::FilePath& dir) { |
| return dir.Append("icons").Append(theme_dir); |
| }); |
| } |
| return retval; |
| } |
| |
| } // namespace |
| |
| std::vector<base::FilePath> GetPathsForIcons(const base::FilePath& icon_dir, |
| int icon_size, |
| int scale) { |
| std::unique_ptr<IconIndexFile> icon_index_file = |
| IconIndexFile::ParseIconIndexFile(icon_dir); |
| if (icon_index_file) { |
| return icon_index_file->GetPathsForSizeAndScale(icon_size, scale); |
| } else { |
| // Index files aren't always present, so do our best to try to find |
| // something that'll work. |
| std::vector<base::FilePath> retval; |
| retval.emplace_back( |
| icon_dir.Append(base::StringPrintf("%dx%d", icon_size, icon_size)) |
| .Append(kDefaultIconSubdir)); |
| for (auto curr_size : kDefaultIconSizeDirs) { |
| if (curr_size != icon_size) { |
| retval.emplace_back( |
| icon_dir.Append(base::StringPrintf("%dx%d", curr_size, curr_size)) |
| .Append(kDefaultIconSubdir)); |
| } |
| } |
| return retval; |
| } |
| } |
| |
| base::FilePath LocateIconFile(const std::string& desktop_file_id, |
| int icon_size, |
| int scale) { |
| base::FilePath desktop_file_path = |
| DesktopFile::FindFileForDesktopId(desktop_file_id); |
| if (desktop_file_path.empty()) { |
| LOG(ERROR) << "Failed to find desktop file for " << desktop_file_id; |
| return base::FilePath(); |
| } |
| std::unique_ptr<DesktopFile> desktop_file = |
| DesktopFile::ParseDesktopFile(desktop_file_path); |
| if (!desktop_file) { |
| LOG(ERROR) << "Failed to parse desktop file " << desktop_file_path.value(); |
| return base::FilePath(); |
| } |
| if (desktop_file->icon().empty()) { |
| return base::FilePath(); |
| } |
| const base::FilePath desktop_file_icon_filepath(desktop_file->icon()); |
| if (desktop_file_icon_filepath.IsAbsolute()) { |
| if (desktop_file_icon_filepath.Extension() == ".png") { |
| return desktop_file_icon_filepath; |
| } else { |
| LOG(INFO) << desktop_file_id << " icon file is not a png file"; |
| return base::FilePath(); |
| } |
| } |
| std::string icon_filename = |
| desktop_file_icon_filepath.AddExtension("png").value(); |
| for (const base::FilePath& icon_dir : GetPathsForIconIndexDirs()) { |
| for (const base::FilePath& curr_path : |
| GetPathsForIcons(icon_dir, icon_size, scale)) { |
| base::FilePath test_path = curr_path.Append(icon_filename); |
| if (base::PathExists(test_path)) |
| return test_path; |
| } |
| } |
| |
| // Also check the default pixmaps dir as a last resort. |
| base::FilePath test_path = |
| base::FilePath(kDefaultPixmapsDir).Append(icon_filename); |
| if (base::PathExists(test_path)) |
| return test_path; |
| |
| LOG(INFO) << "No icon file found for " << desktop_file_id; |
| return base::FilePath(); |
| } |
| |
| } // namespace garcon |
| } // namespace vm_tools |