OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/mime_util.h" | 5 #include "base/mime_util.h" |
6 | 6 |
7 #include <sys/time.h> | |
8 #include <time.h> | |
9 | 7 |
10 #include <cstdlib> | 8 #include <cstdlib> |
11 #include <list> | 9 #include <list> |
12 #include <map> | 10 #include <map> |
13 #include <vector> | 11 #include <vector> |
14 | 12 |
15 #include "base/environment.h" | 13 #include "base/environment.h" |
16 #include "base/file_util.h" | 14 #include "base/file_util.h" |
17 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
18 #include "base/logging.h" | 16 #include "base/logging.h" |
19 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
20 #include "base/memory/singleton.h" | 18 #include "base/memory/singleton.h" |
21 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
22 #include "base/nix/xdg_util.h" | 20 #include "base/nix/xdg_util.h" |
23 #include "base/string_split.h" | 21 #include "base/string_split.h" |
24 #include "base/string_util.h" | 22 #include "base/string_util.h" |
25 #include "base/synchronization/lock.h" | 23 #include "base/synchronization/lock.h" |
26 #include "base/third_party/xdg_mime/xdgmime.h" | 24 #include "base/third_party/xdg_mime/xdgmime.h" |
27 #include "base/threading/thread_restrictions.h" | 25 #include "base/threading/thread_restrictions.h" |
| 26 #include "base/time.h" |
28 | 27 |
29 #if defined(TOOLKIT_USES_GTK) | 28 #if defined(TOOLKIT_USES_GTK) |
30 #include <gtk/gtk.h> | 29 #include <gtk/gtk.h> |
31 #endif | 30 #endif |
32 | 31 |
33 namespace { | 32 namespace { |
34 | 33 |
35 // None of the XDG stuff is thread-safe, so serialize all access under | 34 // None of the XDG stuff is thread-safe, so serialize all access under |
36 // this lock. | 35 // this lock. |
37 static base::LazyInstance<base::Lock, | 36 static base::LazyInstance<base::Lock, |
38 base::LeakyLazyInstanceTraits<base::Lock> > | 37 base::LeakyLazyInstanceTraits<base::Lock> > |
39 g_mime_util_xdg_lock(base::LINKER_INITIALIZED); | 38 g_mime_util_xdg_lock(base::LINKER_INITIALIZED); |
40 | 39 |
41 class IconTheme; | 40 class IconTheme; |
42 | 41 |
43 class MimeUtilConstants { | 42 class MimeUtilConstants { |
44 public: | 43 public: |
45 typedef std::map<std::string, IconTheme*> IconThemeMap; | 44 typedef std::map<std::string, IconTheme*> IconThemeMap; |
46 typedef std::map<FilePath, int> IconDirMtimeMap; | 45 typedef std::map<FilePath, base::Time> IconDirMtimeMap; |
47 typedef std::vector<std::string> IconFormats; | 46 typedef std::vector<std::string> IconFormats; |
48 | 47 |
49 // In seconds, specified by icon theme specs. | 48 // Specified by XDG icon theme specs. |
50 static const int kUpdateInterval = 5; | 49 static const int kUpdateIntervalInSeconds = 5; |
51 | 50 |
52 static const size_t kDefaultThemeNum = 4; | 51 static const size_t kDefaultThemeNum = 4; |
53 | 52 |
54 static MimeUtilConstants* GetInstance() { | 53 static MimeUtilConstants* GetInstance() { |
55 return Singleton<MimeUtilConstants>::get(); | 54 return Singleton<MimeUtilConstants>::get(); |
56 } | 55 } |
57 | 56 |
58 // Store icon directories and their mtimes. | 57 // Store icon directories and their mtimes. |
59 IconDirMtimeMap icon_dirs_; | 58 IconDirMtimeMap icon_dirs_; |
60 | 59 |
61 // Store icon formats. | 60 // Store icon formats. |
62 IconFormats icon_formats_; | 61 IconFormats icon_formats_; |
63 | 62 |
64 // Store loaded icon_theme. | 63 // Store loaded icon_theme. |
65 IconThemeMap icon_themes_; | 64 IconThemeMap icon_themes_; |
66 | 65 |
67 // The default theme. | 66 // The default theme. |
68 IconTheme* default_themes_[kDefaultThemeNum]; | 67 IconTheme* default_themes_[kDefaultThemeNum]; |
69 | 68 |
70 time_t last_check_time_; | 69 base::TimeTicks last_check_time_; |
71 | 70 |
72 #if defined(TOOLKIT_USES_GTK) | 71 #if defined(TOOLKIT_USES_GTK) |
73 // This is set by DetectGtkTheme(). We cache it so that we can access the | 72 // This is set by DetectGtkTheme(). We cache it so that we can access the |
74 // theme name from threads that aren't allowed to call | 73 // theme name from threads that aren't allowed to call |
75 // gtk_settings_get_default(). | 74 // gtk_settings_get_default(). |
76 std::string gtk_theme_name_; | 75 std::string gtk_theme_name_; |
77 #endif | 76 #endif |
78 | 77 |
79 private: | 78 private: |
80 MimeUtilConstants() | 79 MimeUtilConstants() { |
81 : last_check_time_(0) { | |
82 icon_formats_.push_back(".png"); | 80 icon_formats_.push_back(".png"); |
83 icon_formats_.push_back(".svg"); | 81 icon_formats_.push_back(".svg"); |
84 icon_formats_.push_back(".xpm"); | 82 icon_formats_.push_back(".xpm"); |
85 | 83 |
86 for (size_t i = 0; i < kDefaultThemeNum; ++i) | 84 for (size_t i = 0; i < kDefaultThemeNum; ++i) |
87 default_themes_[i] = NULL; | 85 default_themes_[i] = NULL; |
88 } | 86 } |
89 ~MimeUtilConstants(); | 87 ~MimeUtilConstants(); |
90 | 88 |
91 friend struct DefaultSingletonTraits<MimeUtilConstants>; | 89 friend struct DefaultSingletonTraits<MimeUtilConstants>; |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir); | 387 TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir); |
390 if (dir.length() == 0) { | 388 if (dir.length() == 0) { |
391 DLOG(WARNING) << "Invalid index.theme: blank subdir"; | 389 DLOG(WARNING) << "Invalid index.theme: blank subdir"; |
392 return false; | 390 return false; |
393 } | 391 } |
394 subdirs_[dir] = num++; | 392 subdirs_[dir] = num++; |
395 info_array_.reset(new SubDirInfo[num]); | 393 info_array_.reset(new SubDirInfo[num]); |
396 return true; | 394 return true; |
397 } | 395 } |
398 | 396 |
| 397 bool CheckDirExistsAndGetMtime(const FilePath& dir, |
| 398 base::Time* last_modified) { |
| 399 if (!file_util::DirectoryExists(dir)) |
| 400 return false; |
| 401 base::PlatformFileInfo file_info; |
| 402 if (!file_util::GetFileInfo(dir, &file_info)) |
| 403 return false; |
| 404 *last_modified = file_info.last_modified; |
| 405 return true; |
| 406 } |
| 407 |
399 // Make sure |dir| exists and add it to the list of icon directories. | 408 // Make sure |dir| exists and add it to the list of icon directories. |
400 void TryAddIconDir(const FilePath& dir) { | 409 void TryAddIconDir(const FilePath& dir) { |
401 if (!file_util::DirectoryExists(dir)) | 410 base::Time last_modified; |
| 411 if (!CheckDirExistsAndGetMtime(dir, &last_modified)) |
402 return; | 412 return; |
403 MimeUtilConstants::GetInstance()->icon_dirs_[dir] = 0; | 413 MimeUtilConstants::GetInstance()->icon_dirs_[dir] = last_modified; |
404 } | 414 } |
405 | 415 |
406 // For a xdg directory |dir|, add the appropriate icon sub-directories. | 416 // For a xdg directory |dir|, add the appropriate icon sub-directories. |
407 void AddXDGDataDir(const FilePath& dir) { | 417 void AddXDGDataDir(const FilePath& dir) { |
408 if (!file_util::DirectoryExists(dir)) | 418 if (!file_util::DirectoryExists(dir)) |
409 return; | 419 return; |
410 TryAddIconDir(dir.Append("icons")); | 420 TryAddIconDir(dir.Append("icons")); |
411 TryAddIconDir(dir.Append("pixmaps")); | 421 TryAddIconDir(dir.Append("pixmaps")); |
412 } | 422 } |
413 | 423 |
414 // Add all the xdg icon directories. | 424 // Add all the xdg icon directories. |
415 void InitIconDir() { | 425 void InitIconDir() { |
416 MimeUtilConstants::GetInstance()->icon_dirs_.clear(); | |
417 FilePath home = file_util::GetHomeDir(); | 426 FilePath home = file_util::GetHomeDir(); |
418 if (!home.empty()) { | 427 if (!home.empty()) { |
419 FilePath legacy_data_dir(home); | 428 FilePath legacy_data_dir(home); |
420 legacy_data_dir = legacy_data_dir.AppendASCII(".icons"); | 429 legacy_data_dir = legacy_data_dir.AppendASCII(".icons"); |
421 if (file_util::DirectoryExists(legacy_data_dir)) | 430 if (file_util::DirectoryExists(legacy_data_dir)) |
422 TryAddIconDir(legacy_data_dir); | 431 TryAddIconDir(legacy_data_dir); |
423 } | 432 } |
424 const char* env = getenv("XDG_DATA_HOME"); | 433 const char* env = getenv("XDG_DATA_HOME"); |
425 if (env) { | 434 if (env) { |
426 AddXDGDataDir(FilePath(env)); | 435 AddXDGDataDir(FilePath(env)); |
(...skipping 12 matching lines...) Expand all Loading... |
439 std::string xdg_data_dirs = env; | 448 std::string xdg_data_dirs = env; |
440 std::string::size_type pos = 0, epos; | 449 std::string::size_type pos = 0, epos; |
441 while ((epos = xdg_data_dirs.find(':', pos)) != std::string::npos) { | 450 while ((epos = xdg_data_dirs.find(':', pos)) != std::string::npos) { |
442 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos))); | 451 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos))); |
443 pos = epos + 1; | 452 pos = epos + 1; |
444 } | 453 } |
445 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); | 454 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); |
446 } | 455 } |
447 } | 456 } |
448 | 457 |
449 // Per xdg theme spec, we should check the icon directories every so often for | |
450 // newly added icons. This isn't quite right. | |
451 void EnsureUpdated() { | 458 void EnsureUpdated() { |
452 struct timeval t; | |
453 gettimeofday(&t, NULL); | |
454 time_t now = t.tv_sec; | |
455 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); | 459 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); |
| 460 if (constants->last_check_time_.is_null()) { |
| 461 constants->last_check_time_ = base::TimeTicks::Now(); |
| 462 InitIconDir(); |
| 463 return; |
| 464 } |
456 | 465 |
457 if (constants->last_check_time_ == 0) { | 466 // Per xdg theme spec, we should check the icon directories every so often |
458 InitIconDir(); | 467 // for newly added icons. |
459 constants->last_check_time_ = now; | 468 base::TimeDelta time_since_last_check = |
460 } else { | 469 base::TimeTicks::Now() - constants->last_check_time_; |
461 // TODO(thestig): something changed. start over. Upstream fix to Google | 470 if (time_since_last_check.InSeconds() > constants->kUpdateIntervalInSeconds) { |
462 // Gadgets for Linux. | 471 constants->last_check_time_ += time_since_last_check; |
463 if (now > constants->last_check_time_ + constants->kUpdateInterval) { | 472 |
| 473 bool rescan_icon_dirs = false; |
| 474 MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; |
| 475 MimeUtilConstants::IconDirMtimeMap::iterator iter; |
| 476 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { |
| 477 base::Time last_modified; |
| 478 if (!CheckDirExistsAndGetMtime(iter->first, &last_modified) || |
| 479 last_modified != iter->second) { |
| 480 rescan_icon_dirs = true; |
| 481 break; |
| 482 } |
| 483 } |
| 484 |
| 485 if (rescan_icon_dirs) { |
| 486 constants->icon_dirs_.clear(); |
| 487 constants->icon_themes_.clear(); |
| 488 InitIconDir(); |
464 } | 489 } |
465 } | 490 } |
466 } | 491 } |
467 | 492 |
468 // Find a fallback icon if we cannot find it in the default theme. | 493 // Find a fallback icon if we cannot find it in the default theme. |
469 FilePath LookupFallbackIcon(const std::string& icon_name) { | 494 FilePath LookupFallbackIcon(const std::string& icon_name) { |
470 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); | 495 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); |
471 MimeUtilConstants::IconDirMtimeMap::iterator iter; | 496 MimeUtilConstants::IconDirMtimeMap::iterator iter; |
472 MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; | 497 MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; |
473 MimeUtilConstants::IconFormats* icon_formats = &constants->icon_formats_; | 498 MimeUtilConstants::IconFormats* icon_formats = &constants->icon_formats_; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 } else { | 666 } else { |
642 icon_file = LookupIconInDefaultTheme(icon_names[i], size); | 667 icon_file = LookupIconInDefaultTheme(icon_names[i], size); |
643 if (!icon_file.empty()) | 668 if (!icon_file.empty()) |
644 return icon_file; | 669 return icon_file; |
645 } | 670 } |
646 } | 671 } |
647 return FilePath(); | 672 return FilePath(); |
648 } | 673 } |
649 | 674 |
650 } // namespace mime_util | 675 } // namespace mime_util |
OLD | NEW |