mime_util_xdg.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/nix/mime_util_xdg.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstdlib>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/nix/xdg_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_split.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/third_party/xdg_mime/xdgmime.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gtk/gtk.h>  // NOLINT
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IconTheme;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// None of the XDG stuff is thread-safe, so serialize all access under
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this lock.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<base::Lock>::Leaky
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MimeUtilConstants {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<std::string, IconTheme*> IconThemeMap;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<FilePath, base::Time> IconDirMtimeMap;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::vector<std::string> IconFormats;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Specified by XDG icon theme specs.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kUpdateIntervalInSeconds = 5;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kDefaultThemeNum = 4;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static MimeUtilConstants* GetInstance() {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<MimeUtilConstants>::get();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Store icon directories and their mtimes.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconDirMtimeMap icon_dirs_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Store icon formats.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconFormats icon_formats_;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Store loaded icon_theme.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconThemeMap icon_themes_;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default theme.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconTheme* default_themes_[kDefaultThemeNum];
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks last_check_time_;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is set by DetectGtkTheme(). We cache it so that we can access the
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // theme name from threads that aren't allowed to call
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gtk_settings_get_default().
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string gtk_theme_name_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants() {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_formats_.push_back(".png");
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_formats_.push_back(".svg");
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_formats_.push_back(".xpm");
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < kDefaultThemeNum; ++i)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_themes_[i] = NULL;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~MimeUtilConstants();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<MimeUtilConstants>;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MimeUtilConstants);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IconTheme represents an icon theme as defined by the xdg icon theme spec.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Example themes on GNOME include 'Human' and 'Mist'.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Example themes on KDE include 'crystalsvg' and 'kdeclassic'.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IconTheme {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A theme consists of multiple sub-directories, like '32x32' and 'scalable'.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class SubDirInfo {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See spec for details.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enum Type {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Fixed,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Scalable,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Threshold
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SubDirInfo()
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : size(0),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          type(Threshold),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          max_size(0),
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          min_size(0),
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          threshold(2) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t size;  // Nominal size of the icons in this directory.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Type type;  // Type of the icon size.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t max_size;  // Maximum size that the icons can be scaled to.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t min_size;  // Minimum size that the icons can be scaled to.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t threshold;  // Maximum difference from desired size. 2 by default.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit IconTheme(const std::string& name);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~IconTheme() {}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the path to an icon with the name |icon_name| and a size of |size|
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pixels. If the icon does not exist, but |inherits| is true, then look for
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the icon in the parent theme.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath GetIconPath(const std::string& icon_name, int size, bool inherits);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Load a theme with the name |theme_name| into memory. Returns null if theme
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is invalid.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static IconTheme* LoadTheme(const std::string& theme_name);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the path to an icon with the name |icon_name| in |subdir|.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath GetIconPathUnderSubdir(const std::string& icon_name,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::string& subdir);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether the theme loaded properly.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsValid() {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return index_theme_loaded_;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read and parse |file| which is usually named 'index.theme' per theme spec.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool LoadIndexTheme(const FilePath& file);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Checks to see if the icons in |info| matches |size| (in pixels). Returns
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 0 if they match, or the size difference in pixels.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t MatchesSize(SubDirInfo* info, size_t size);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Yet another function to read a line.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ReadLine(FILE* fp);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set directories to search for icons to the comma-separated list |dirs|.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool SetDirectories(const std::string& dirs);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool index_theme_loaded_;  // True if an instance is properly loaded.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // store the scattered directories of this theme.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::list<FilePath> dirs_;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // store the subdirs of this theme and array index of |info_array_|.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, int> subdirs_;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_array<SubDirInfo> info_array_;  // List of sub-directories.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string inherits_;  // Name of the theme this one inherits from.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IconTheme::IconTheme(const std::string& name)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : index_theme_loaded_(false),
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info_array_(NULL) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate on all icon directories to find directories of the specified
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // theme and load the first encountered index.theme.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconDirMtimeMap::iterator iter;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath theme_path;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconDirMtimeMap* icon_dirs =
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &MimeUtilConstants::GetInstance()->icon_dirs_;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    theme_path = iter->first.Append(name);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!file_util::DirectoryExists(theme_path))
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilePath theme_index = theme_path.Append("index.theme");
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!index_theme_loaded_ && file_util::PathExists(theme_index)) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!LoadIndexTheme(theme_index))
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_theme_loaded_ = true;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dirs_.push_back(theme_path);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath IconTheme::GetIconPath(const std::string& icon_name, int size,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                bool inherits) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, int>::iterator subdir_iter;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath icon_path;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (subdir_iter = subdirs_.begin();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       subdir_iter != subdirs_.end();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++subdir_iter) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SubDirInfo* info = &info_array_[subdir_iter->second];
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MatchesSize(info, size) == 0) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_path = GetIconPathUnderSubdir(icon_name, subdir_iter->first);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!icon_path.empty())
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return icon_path;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now looking for the mostly matched.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t min_delta_seen = 9999;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (subdir_iter = subdirs_.begin();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       subdir_iter != subdirs_.end();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++subdir_iter) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SubDirInfo* info = &info_array_[subdir_iter->second];
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t delta = MatchesSize(info, size);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delta < min_delta_seen) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePath path = GetIconPathUnderSubdir(icon_name, subdir_iter->first);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!path.empty()) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        min_delta_seen = delta;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon_path = path;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!icon_path.empty() || !inherits || inherits_ == "")
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return icon_path;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconTheme* theme = LoadTheme(inherits_);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inheriting from itself means the theme is buggy but we shouldn't crash.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (theme && theme != this)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return theme->GetIconPath(icon_name, size, inherits);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FilePath();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IconTheme* IconTheme::LoadTheme(const std::string& theme_name) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<IconTheme> theme;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconThemeMap* icon_themes =
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &MimeUtilConstants::GetInstance()->icon_themes_;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_themes->find(theme_name) != icon_themes->end()) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    theme.reset((*icon_themes)[theme_name]);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    theme.reset(new IconTheme(theme_name));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!theme->IsValid())
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      theme.reset();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*icon_themes)[theme_name] = theme.get();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return theme.release();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const std::string& subdir) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath icon_path;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::list<FilePath>::iterator dir_iter;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconFormats* icon_formats =
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &MimeUtilConstants::GetInstance()->icon_formats_;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < icon_formats->size(); ++i) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_path = dir_iter->Append(subdir);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_path = icon_path.Append(icon_name + (*icon_formats)[i]);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (file_util::PathExists(icon_path))
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return icon_path;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FilePath();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IconTheme::LoadIndexTheme(const FilePath& file) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILE* fp = file_util::OpenFile(file, "r");
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SubDirInfo* current_info = NULL;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!fp)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read entries.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!feof(fp) && !ferror(fp)) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string buf = ReadLine(fp);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buf == "")
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string entry;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrimWhitespaceASCII(buf, TRIM_ALL, &entry);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry.length() == 0 || entry[0] == '#') {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Blank line or Comment.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (entry[0] == '[' && info_array_.get()) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current_info = NULL;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string subdir = entry.substr(1, entry.length() - 2);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (subdirs_.find(subdir) != subdirs_.end())
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_info = &info_array_[subdirs_[subdir]];
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string key, value;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> r;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitStringDontTrim(entry, '=', &r);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (r.size() < 2)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrimWhitespaceASCII(r[0], TRIM_ALL, &key);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 1; i < r.size(); i++)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value.append(r[i]);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrimWhitespaceASCII(value, TRIM_ALL, &value);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_info) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (key == "Size") {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_info->size = atoi(value.c_str());
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (key == "Type") {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (value == "Fixed")
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_info->type = SubDirInfo::Fixed;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else if (value == "Scalable")
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_info->type = SubDirInfo::Scalable;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else if (value == "Threshold")
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_info->type = SubDirInfo::Threshold;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (key == "MaxSize") {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_info->max_size = atoi(value.c_str());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (key == "MinSize") {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_info->min_size = atoi(value.c_str());
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (key == "Threshold") {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_info->threshold = atoi(value.c_str());
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (key.compare("Directories") == 0 && !info_array_.get()) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SetDirectories(value)) break;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (key.compare("Inherits") == 0) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (value != "hicolor")
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          inherits_ = value;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::CloseFile(fp);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return info_array_.get() != NULL;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t IconTheme::MatchesSize(SubDirInfo* info, size_t size) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (info->type == SubDirInfo::Fixed) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > info->size)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return size - info->size;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return info->size - size;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (info->type == SubDirInfo::Scalable) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size < info->min_size)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return info->min_size - size;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > info->max_size)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return size - info->max_size;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size + info->threshold < info->size)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return info->size - size - info->threshold;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > info->size + info->threshold)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return size - info->size - info->threshold;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string IconTheme::ReadLine(FILE* fp) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!fp)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "";
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string result = "";
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t kBufferSize = 100;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buffer[kBufferSize];
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ((fgets(buffer, kBufferSize - 1, fp)) != NULL) {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result += buffer;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t len = result.length();
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len == 0)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char end = result[len - 1];
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (end == '\n' || end == '\0')
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IconTheme::SetDirectories(const std::string& dirs) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num = 0;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string::size_type pos = 0, epos;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string dir;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ((epos = dirs.find(',', pos)) != std::string::npos) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TrimWhitespaceASCII(dirs.substr(pos, epos - pos), TRIM_ALL, &dir);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dir.length() == 0) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(WARNING) << "Invalid index.theme: blank subdir";
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    subdirs_[dir] = num++;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pos = epos + 1;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dir.length() == 0) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Invalid index.theme: blank subdir";
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subdirs_[dir] = num++;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info_array_.reset(new SubDirInfo[num]);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckDirExistsAndGetMtime(const FilePath& dir,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::Time* last_modified) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_util::DirectoryExists(dir))
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PlatformFileInfo file_info;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_util::GetFileInfo(dir, &file_info))
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *last_modified = file_info.last_modified;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Make sure |dir| exists and add it to the list of icon directories.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TryAddIconDir(const FilePath& dir) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time last_modified;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CheckDirExistsAndGetMtime(dir, &last_modified))
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::GetInstance()->icon_dirs_[dir] = last_modified;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For a xdg directory |dir|, add the appropriate icon sub-directories.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AddXDGDataDir(const FilePath& dir) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_util::DirectoryExists(dir))
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TryAddIconDir(dir.Append("icons"));
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TryAddIconDir(dir.Append("pixmaps"));
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Add all the xdg icon directories.
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitIconDir() {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath home = file_util::GetHomeDir();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!home.empty()) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePath legacy_data_dir(home);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      legacy_data_dir = legacy_data_dir.AppendASCII(".icons");
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (file_util::DirectoryExists(legacy_data_dir))
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TryAddIconDir(legacy_data_dir);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* env = getenv("XDG_DATA_HOME");
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (env) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddXDGDataDir(FilePath(env));
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!home.empty()) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilePath local_data_dir(home);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_data_dir = local_data_dir.AppendASCII(".local");
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_data_dir = local_data_dir.AppendASCII("share");
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddXDGDataDir(local_data_dir);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  env = getenv("XDG_DATA_DIRS");
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!env) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddXDGDataDir(FilePath("/usr/local/share"));
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddXDGDataDir(FilePath("/usr/share"));
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string xdg_data_dirs = env;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string::size_type pos = 0, epos;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while ((epos = xdg_data_dirs.find(':', pos)) != std::string::npos) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos)));
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pos = epos + 1;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos)));
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnsureUpdated() {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (constants->last_check_time_.is_null()) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    constants->last_check_time_ = base::TimeTicks::Now();
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitIconDir();
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Per xdg theme spec, we should check the icon directories every so often
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for newly added icons.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta time_since_last_check =
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeTicks::Now() - constants->last_check_time_;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (time_since_last_check.InSeconds() > constants->kUpdateIntervalInSeconds) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    constants->last_check_time_ += time_since_last_check;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool rescan_icon_dirs = false;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MimeUtilConstants::IconDirMtimeMap::iterator iter;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Time last_modified;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!CheckDirExistsAndGetMtime(iter->first, &last_modified) ||
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          last_modified != iter->second) {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rescan_icon_dirs = true;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rescan_icon_dirs) {
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      constants->icon_dirs_.clear();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      constants->icon_themes_.clear();
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InitIconDir();
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find a fallback icon if we cannot find it in the default theme.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath LookupFallbackIcon(const std::string& icon_name) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconDirMtimeMap::iterator iter;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconFormats* icon_formats = &constants->icon_formats_;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < icon_formats->size(); ++i) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePath icon = iter->first.Append(icon_name + (*icon_formats)[i]);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (file_util::PathExists(icon))
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return icon;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FilePath();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Initialize the list of default themes.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitDefaultThemes() {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconTheme** default_themes =
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MimeUtilConstants::GetInstance()->default_themes_;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::nix::DesktopEnvironment desktop_env =
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::nix::GetDesktopEnvironment(env.get());
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3 ||
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // KDE
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string kde_default_theme;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string kde_fallback_theme;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(thestig): Figure out how to get the current icon theme on KDE.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_themes[0] = NULL;
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try some reasonable defaults for KDE.
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3) {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // KDE 3
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kde_default_theme = "default.kde";
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kde_fallback_theme = "crystalsvg";
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // KDE 4
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kde_default_theme = "default.kde4";
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kde_fallback_theme = "oxygen";
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_themes[1] = IconTheme::LoadTheme(kde_default_theme);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_themes[2] = IconTheme::LoadTheme(kde_fallback_theme);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Assume it's Gnome and use GTK to figure out the theme.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_themes[1] = IconTheme::LoadTheme(
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        MimeUtilConstants::GetInstance()->gtk_theme_name_);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_themes[2] = IconTheme::LoadTheme("gnome");
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // hicolor needs to be last per icon theme spec.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_themes[3] = IconTheme::LoadTheme("hicolor");
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) {
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (default_themes[i] == NULL)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NULL out duplicate pointers.
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = i + 1; j < MimeUtilConstants::kDefaultThemeNum; j++) {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (default_themes[j] == default_themes[i])
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default_themes[j] = NULL;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Try to find an icon with the name |icon_name| that's |size| pixels.
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureUpdated();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::IconThemeMap* icon_themes = &constants->icon_themes_;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_themes->empty())
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitDefaultThemes();
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath icon_path;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IconTheme** default_themes = constants->default_themes_;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (default_themes[i]) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_path = default_themes[i]->GetIconPath(icon_name, size, true);
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!icon_path.empty())
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return icon_path;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LookupFallbackIcon(icon_name);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MimeUtilConstants::~MimeUtilConstants() {
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < kDefaultThemeNum; i++)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete default_themes_[i];
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace nix {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetFileMimeType(const FilePath& filepath) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (filepath.empty())
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string();
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str());
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetDataMimeType(const std::string& data) {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL);
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_GTK)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DetectGtkTheme() {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the theme name is already loaded, do nothing. Chrome doesn't respond
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to changes in the system theme, so we never need to set this more than
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // once.
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MimeUtilConstants::GetInstance()->gtk_theme_name_.empty())
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should only be called on the UI thread.
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gchar* gtk_theme_name;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_get(gtk_settings_get_default(),
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               "gtk-icon-theme-name",
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               &gtk_theme_name, NULL);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MimeUtilConstants::GetInstance()->gtk_theme_name_.assign(gtk_theme_name);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_free(gtk_theme_name);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath GetMimeIcon(const std::string& mime_type, size_t size) {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> icon_names;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string icon_name;
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath icon_file;
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!mime_type.empty()) {
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char *icon = xdg_mime_get_icon(mime_type.c_str());
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_name = std::string(icon ? icon : "");
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (icon_name.length())
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_names.push_back(icon_name);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For text/plain, try text-plain.
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_name = mime_type;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = icon_name.find('/', 0); i != std::string::npos;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i = icon_name.find('/', i + 1)) {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_name[i] = '-';
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_names.push_back(icon_name);
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Also try gnome-mime-text-plain.
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_names.push_back("gnome-mime-" + icon_name);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try "deb" for "application/x-deb" in KDE 3.
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t x_substr_pos = mime_type.find("/x-");
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (x_substr_pos != std::string::npos) {
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_name = mime_type.substr(x_substr_pos + 3);
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    icon_names.push_back(icon_name);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try generic name like text-x-generic.
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_name = mime_type.substr(0, mime_type.find('/')) + "-x-generic";
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_names.push_back(icon_name);
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Last resort
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_names.push_back("unknown");
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < icon_names.size(); i++) {
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_names[i][0] == '/') {
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_file = FilePath(icon_names[i]);
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (file_util::PathExists(icon_file))
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return icon_file;
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_file = LookupIconInDefaultTheme(icon_names[i], size);
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!icon_file.empty())
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return icon_file;
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FilePath();
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace nix
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
679