| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/nix/mime_util_xdg.h" | 5 #include "base/nix/mime_util_xdg.h" |
| 6 | 6 |
| 7 #include <cstdlib> | 7 #include <cstdlib> |
| 8 #include <list> | 8 #include <list> |
| 9 #include <map> | 9 #include <map> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 namespace base { | 26 namespace base { |
| 27 namespace nix { | 27 namespace nix { |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 class IconTheme; | 31 class IconTheme; |
| 32 | 32 |
| 33 // None of the XDG stuff is thread-safe, so serialize all access under | 33 // None of the XDG stuff is thread-safe, so serialize all access under |
| 34 // this lock. | 34 // this lock. |
| 35 base::LazyInstance<base::Lock>::Leaky | 35 LazyInstance<Lock>::Leaky g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER; |
| 36 g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER; | |
| 37 | 36 |
| 38 class MimeUtilConstants { | 37 class MimeUtilConstants { |
| 39 public: | 38 public: |
| 40 typedef std::map<std::string, IconTheme*> IconThemeMap; | 39 typedef std::map<std::string, IconTheme*> IconThemeMap; |
| 41 typedef std::map<FilePath, base::Time> IconDirMtimeMap; | 40 typedef std::map<FilePath, Time> IconDirMtimeMap; |
| 42 typedef std::vector<std::string> IconFormats; | 41 typedef std::vector<std::string> IconFormats; |
| 43 | 42 |
| 44 // Specified by XDG icon theme specs. | 43 // Specified by XDG icon theme specs. |
| 45 static const int kUpdateIntervalInSeconds = 5; | 44 static const int kUpdateIntervalInSeconds = 5; |
| 46 | 45 |
| 47 static const size_t kDefaultThemeNum = 4; | 46 static const size_t kDefaultThemeNum = 4; |
| 48 | 47 |
| 49 static MimeUtilConstants* GetInstance() { | 48 static MimeUtilConstants* GetInstance() { |
| 50 return Singleton<MimeUtilConstants>::get(); | 49 return Singleton<MimeUtilConstants>::get(); |
| 51 } | 50 } |
| 52 | 51 |
| 53 // Store icon directories and their mtimes. | 52 // Store icon directories and their mtimes. |
| 54 IconDirMtimeMap icon_dirs_; | 53 IconDirMtimeMap icon_dirs_; |
| 55 | 54 |
| 56 // Store icon formats. | 55 // Store icon formats. |
| 57 IconFormats icon_formats_; | 56 IconFormats icon_formats_; |
| 58 | 57 |
| 59 // Store loaded icon_theme. | 58 // Store loaded icon_theme. |
| 60 IconThemeMap icon_themes_; | 59 IconThemeMap icon_themes_; |
| 61 | 60 |
| 62 // The default theme. | 61 // The default theme. |
| 63 IconTheme* default_themes_[kDefaultThemeNum]; | 62 IconTheme* default_themes_[kDefaultThemeNum]; |
| 64 | 63 |
| 65 base::TimeTicks last_check_time_; | 64 TimeTicks last_check_time_; |
| 66 | 65 |
| 67 // The current icon theme, usually set through GTK theme integration. | 66 // The current icon theme, usually set through GTK theme integration. |
| 68 std::string icon_theme_name_; | 67 std::string icon_theme_name_; |
| 69 | 68 |
| 70 private: | 69 private: |
| 71 MimeUtilConstants() { | 70 MimeUtilConstants() { |
| 72 icon_formats_.push_back(".png"); | 71 icon_formats_.push_back(".png"); |
| 73 icon_formats_.push_back(".svg"); | 72 icon_formats_.push_back(".svg"); |
| 74 icon_formats_.push_back(".xpm"); | 73 icon_formats_.push_back(".xpm"); |
| 75 | 74 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 std::list<FilePath> dirs_; | 151 std::list<FilePath> dirs_; |
| 153 | 152 |
| 154 // store the subdirs of this theme and array index of |info_array_|. | 153 // store the subdirs of this theme and array index of |info_array_|. |
| 155 std::map<std::string, int> subdirs_; | 154 std::map<std::string, int> subdirs_; |
| 156 scoped_ptr<SubDirInfo[]> info_array_; // List of sub-directories. | 155 scoped_ptr<SubDirInfo[]> info_array_; // List of sub-directories. |
| 157 std::string inherits_; // Name of the theme this one inherits from. | 156 std::string inherits_; // Name of the theme this one inherits from. |
| 158 }; | 157 }; |
| 159 | 158 |
| 160 IconTheme::IconTheme(const std::string& name) | 159 IconTheme::IconTheme(const std::string& name) |
| 161 : index_theme_loaded_(false) { | 160 : index_theme_loaded_(false) { |
| 162 base::ThreadRestrictions::AssertIOAllowed(); | 161 ThreadRestrictions::AssertIOAllowed(); |
| 163 // Iterate on all icon directories to find directories of the specified | 162 // Iterate on all icon directories to find directories of the specified |
| 164 // theme and load the first encountered index.theme. | 163 // theme and load the first encountered index.theme. |
| 165 MimeUtilConstants::IconDirMtimeMap::iterator iter; | 164 MimeUtilConstants::IconDirMtimeMap::iterator iter; |
| 166 FilePath theme_path; | 165 FilePath theme_path; |
| 167 MimeUtilConstants::IconDirMtimeMap* icon_dirs = | 166 MimeUtilConstants::IconDirMtimeMap* icon_dirs = |
| 168 &MimeUtilConstants::GetInstance()->icon_dirs_; | 167 &MimeUtilConstants::GetInstance()->icon_dirs_; |
| 169 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { | 168 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { |
| 170 theme_path = iter->first.Append(name); | 169 theme_path = iter->first.Append(name); |
| 171 if (!DirectoryExists(theme_path)) | 170 if (!DirectoryExists(theme_path)) |
| 172 continue; | 171 continue; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 continue; | 273 continue; |
| 275 } else if (entry[0] == '[' && info_array_.get()) { | 274 } else if (entry[0] == '[' && info_array_.get()) { |
| 276 current_info = NULL; | 275 current_info = NULL; |
| 277 std::string subdir = entry.substr(1, entry.length() - 2); | 276 std::string subdir = entry.substr(1, entry.length() - 2); |
| 278 if (subdirs_.find(subdir) != subdirs_.end()) | 277 if (subdirs_.find(subdir) != subdirs_.end()) |
| 279 current_info = &info_array_[subdirs_[subdir]]; | 278 current_info = &info_array_[subdirs_[subdir]]; |
| 280 } | 279 } |
| 281 | 280 |
| 282 std::string key, value; | 281 std::string key, value; |
| 283 std::vector<std::string> r; | 282 std::vector<std::string> r; |
| 284 base::SplitStringDontTrim(entry, '=', &r); | 283 SplitStringDontTrim(entry, '=', &r); |
| 285 if (r.size() < 2) | 284 if (r.size() < 2) |
| 286 continue; | 285 continue; |
| 287 | 286 |
| 288 TrimWhitespaceASCII(r[0], TRIM_ALL, &key); | 287 TrimWhitespaceASCII(r[0], TRIM_ALL, &key); |
| 289 for (size_t i = 1; i < r.size(); i++) | 288 for (size_t i = 1; i < r.size(); i++) |
| 290 value.append(r[i]); | 289 value.append(r[i]); |
| 291 TrimWhitespaceASCII(value, TRIM_ALL, &value); | 290 TrimWhitespaceASCII(value, TRIM_ALL, &value); |
| 292 | 291 |
| 293 if (current_info) { | 292 if (current_info) { |
| 294 if (key == "Size") { | 293 if (key == "Size") { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir); | 377 TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir); |
| 379 if (dir.length() == 0) { | 378 if (dir.length() == 0) { |
| 380 DLOG(WARNING) << "Invalid index.theme: blank subdir"; | 379 DLOG(WARNING) << "Invalid index.theme: blank subdir"; |
| 381 return false; | 380 return false; |
| 382 } | 381 } |
| 383 subdirs_[dir] = num++; | 382 subdirs_[dir] = num++; |
| 384 info_array_.reset(new SubDirInfo[num]); | 383 info_array_.reset(new SubDirInfo[num]); |
| 385 return true; | 384 return true; |
| 386 } | 385 } |
| 387 | 386 |
| 388 bool CheckDirExistsAndGetMtime(const FilePath& dir, | 387 bool CheckDirExistsAndGetMtime(const FilePath& dir, Time* last_modified) { |
| 389 base::Time* last_modified) { | |
| 390 if (!DirectoryExists(dir)) | 388 if (!DirectoryExists(dir)) |
| 391 return false; | 389 return false; |
| 392 base::PlatformFileInfo file_info; | 390 PlatformFileInfo file_info; |
| 393 if (!file_util::GetFileInfo(dir, &file_info)) | 391 if (!GetFileInfo(dir, &file_info)) |
| 394 return false; | 392 return false; |
| 395 *last_modified = file_info.last_modified; | 393 *last_modified = file_info.last_modified; |
| 396 return true; | 394 return true; |
| 397 } | 395 } |
| 398 | 396 |
| 399 // Make sure |dir| exists and add it to the list of icon directories. | 397 // Make sure |dir| exists and add it to the list of icon directories. |
| 400 void TryAddIconDir(const FilePath& dir) { | 398 void TryAddIconDir(const FilePath& dir) { |
| 401 base::Time last_modified; | 399 Time last_modified; |
| 402 if (!CheckDirExistsAndGetMtime(dir, &last_modified)) | 400 if (!CheckDirExistsAndGetMtime(dir, &last_modified)) |
| 403 return; | 401 return; |
| 404 MimeUtilConstants::GetInstance()->icon_dirs_[dir] = last_modified; | 402 MimeUtilConstants::GetInstance()->icon_dirs_[dir] = last_modified; |
| 405 } | 403 } |
| 406 | 404 |
| 407 // For a xdg directory |dir|, add the appropriate icon sub-directories. | 405 // For a xdg directory |dir|, add the appropriate icon sub-directories. |
| 408 void AddXDGDataDir(const FilePath& dir) { | 406 void AddXDGDataDir(const FilePath& dir) { |
| 409 if (!DirectoryExists(dir)) | 407 if (!DirectoryExists(dir)) |
| 410 return; | 408 return; |
| 411 TryAddIconDir(dir.Append("icons")); | 409 TryAddIconDir(dir.Append("icons")); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 442 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos))); | 440 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos))); |
| 443 pos = epos + 1; | 441 pos = epos + 1; |
| 444 } | 442 } |
| 445 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); | 443 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); |
| 446 } | 444 } |
| 447 } | 445 } |
| 448 | 446 |
| 449 void EnsureUpdated() { | 447 void EnsureUpdated() { |
| 450 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); | 448 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); |
| 451 if (constants->last_check_time_.is_null()) { | 449 if (constants->last_check_time_.is_null()) { |
| 452 constants->last_check_time_ = base::TimeTicks::Now(); | 450 constants->last_check_time_ = TimeTicks::Now(); |
| 453 InitIconDir(); | 451 InitIconDir(); |
| 454 return; | 452 return; |
| 455 } | 453 } |
| 456 | 454 |
| 457 // Per xdg theme spec, we should check the icon directories every so often | 455 // Per xdg theme spec, we should check the icon directories every so often |
| 458 // for newly added icons. | 456 // for newly added icons. |
| 459 base::TimeDelta time_since_last_check = | 457 TimeDelta time_since_last_check = |
| 460 base::TimeTicks::Now() - constants->last_check_time_; | 458 TimeTicks::Now() - constants->last_check_time_; |
| 461 if (time_since_last_check.InSeconds() > constants->kUpdateIntervalInSeconds) { | 459 if (time_since_last_check.InSeconds() > constants->kUpdateIntervalInSeconds) { |
| 462 constants->last_check_time_ += time_since_last_check; | 460 constants->last_check_time_ += time_since_last_check; |
| 463 | 461 |
| 464 bool rescan_icon_dirs = false; | 462 bool rescan_icon_dirs = false; |
| 465 MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; | 463 MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; |
| 466 MimeUtilConstants::IconDirMtimeMap::iterator iter; | 464 MimeUtilConstants::IconDirMtimeMap::iterator iter; |
| 467 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { | 465 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { |
| 468 base::Time last_modified; | 466 Time last_modified; |
| 469 if (!CheckDirExistsAndGetMtime(iter->first, &last_modified) || | 467 if (!CheckDirExistsAndGetMtime(iter->first, &last_modified) || |
| 470 last_modified != iter->second) { | 468 last_modified != iter->second) { |
| 471 rescan_icon_dirs = true; | 469 rescan_icon_dirs = true; |
| 472 break; | 470 break; |
| 473 } | 471 } |
| 474 } | 472 } |
| 475 | 473 |
| 476 if (rescan_icon_dirs) { | 474 if (rescan_icon_dirs) { |
| 477 constants->icon_dirs_.clear(); | 475 constants->icon_dirs_.clear(); |
| 478 constants->icon_themes_.clear(); | 476 constants->icon_themes_.clear(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 495 } | 493 } |
| 496 } | 494 } |
| 497 return FilePath(); | 495 return FilePath(); |
| 498 } | 496 } |
| 499 | 497 |
| 500 // Initialize the list of default themes. | 498 // Initialize the list of default themes. |
| 501 void InitDefaultThemes() { | 499 void InitDefaultThemes() { |
| 502 IconTheme** default_themes = | 500 IconTheme** default_themes = |
| 503 MimeUtilConstants::GetInstance()->default_themes_; | 501 MimeUtilConstants::GetInstance()->default_themes_; |
| 504 | 502 |
| 505 scoped_ptr<base::Environment> env(base::Environment::Create()); | 503 scoped_ptr<Environment> env(Environment::Create()); |
| 506 base::nix::DesktopEnvironment desktop_env = | 504 base::nix::DesktopEnvironment desktop_env = |
| 507 base::nix::GetDesktopEnvironment(env.get()); | 505 base::nix::GetDesktopEnvironment(env.get()); |
| 508 if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3 || | 506 if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3 || |
| 509 desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) { | 507 desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) { |
| 510 // KDE | 508 // KDE |
| 511 std::string kde_default_theme; | 509 std::string kde_default_theme; |
| 512 std::string kde_fallback_theme; | 510 std::string kde_fallback_theme; |
| 513 | 511 |
| 514 // TODO(thestig): Figure out how to get the current icon theme on KDE. | 512 // TODO(thestig): Figure out how to get the current icon theme on KDE. |
| 515 // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme. | 513 // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 MimeUtilConstants::~MimeUtilConstants() { | 568 MimeUtilConstants::~MimeUtilConstants() { |
| 571 for (size_t i = 0; i < kDefaultThemeNum; i++) | 569 for (size_t i = 0; i < kDefaultThemeNum; i++) |
| 572 delete default_themes_[i]; | 570 delete default_themes_[i]; |
| 573 } | 571 } |
| 574 | 572 |
| 575 } // namespace | 573 } // namespace |
| 576 | 574 |
| 577 std::string GetFileMimeType(const FilePath& filepath) { | 575 std::string GetFileMimeType(const FilePath& filepath) { |
| 578 if (filepath.empty()) | 576 if (filepath.empty()) |
| 579 return std::string(); | 577 return std::string(); |
| 580 base::ThreadRestrictions::AssertIOAllowed(); | 578 ThreadRestrictions::AssertIOAllowed(); |
| 581 base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); | 579 AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); |
| 582 return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str()); | 580 return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str()); |
| 583 } | 581 } |
| 584 | 582 |
| 585 std::string GetDataMimeType(const std::string& data) { | 583 std::string GetDataMimeType(const std::string& data) { |
| 586 base::ThreadRestrictions::AssertIOAllowed(); | 584 ThreadRestrictions::AssertIOAllowed(); |
| 587 base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); | 585 AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); |
| 588 return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL); | 586 return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL); |
| 589 } | 587 } |
| 590 | 588 |
| 591 void SetIconThemeName(const std::string& name) { | 589 void SetIconThemeName(const std::string& name) { |
| 592 // If the theme name is already loaded, do nothing. Chrome doesn't respond | 590 // If the theme name is already loaded, do nothing. Chrome doesn't respond |
| 593 // to changes in the system theme, so we never need to set this more than | 591 // to changes in the system theme, so we never need to set this more than |
| 594 // once. | 592 // once. |
| 595 if (!MimeUtilConstants::GetInstance()->icon_theme_name_.empty()) | 593 if (!MimeUtilConstants::GetInstance()->icon_theme_name_.empty()) |
| 596 return; | 594 return; |
| 597 | 595 |
| 598 MimeUtilConstants::GetInstance()->icon_theme_name_ = name; | 596 MimeUtilConstants::GetInstance()->icon_theme_name_ = name; |
| 599 } | 597 } |
| 600 | 598 |
| 601 FilePath GetMimeIcon(const std::string& mime_type, size_t size) { | 599 FilePath GetMimeIcon(const std::string& mime_type, size_t size) { |
| 602 base::ThreadRestrictions::AssertIOAllowed(); | 600 ThreadRestrictions::AssertIOAllowed(); |
| 603 std::vector<std::string> icon_names; | 601 std::vector<std::string> icon_names; |
| 604 std::string icon_name; | 602 std::string icon_name; |
| 605 FilePath icon_file; | 603 FilePath icon_file; |
| 606 | 604 |
| 607 if (!mime_type.empty()) { | 605 if (!mime_type.empty()) { |
| 608 base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); | 606 AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); |
| 609 const char *icon = xdg_mime_get_icon(mime_type.c_str()); | 607 const char *icon = xdg_mime_get_icon(mime_type.c_str()); |
| 610 icon_name = std::string(icon ? icon : ""); | 608 icon_name = std::string(icon ? icon : ""); |
| 611 } | 609 } |
| 612 | 610 |
| 613 if (icon_name.length()) | 611 if (icon_name.length()) |
| 614 icon_names.push_back(icon_name); | 612 icon_names.push_back(icon_name); |
| 615 | 613 |
| 616 // For text/plain, try text-plain. | 614 // For text/plain, try text-plain. |
| 617 icon_name = mime_type; | 615 icon_name = mime_type; |
| 618 for (size_t i = icon_name.find('/', 0); i != std::string::npos; | 616 for (size_t i = icon_name.find('/', 0); i != std::string::npos; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 646 icon_file = LookupIconInDefaultTheme(icon_names[i], size); | 644 icon_file = LookupIconInDefaultTheme(icon_names[i], size); |
| 647 if (!icon_file.empty()) | 645 if (!icon_file.empty()) |
| 648 return icon_file; | 646 return icon_file; |
| 649 } | 647 } |
| 650 } | 648 } |
| 651 return FilePath(); | 649 return FilePath(); |
| 652 } | 650 } |
| 653 | 651 |
| 654 } // namespace nix | 652 } // namespace nix |
| 655 } // namespace base | 653 } // namespace base |
| OLD | NEW |