| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
| 8 #include <sys/time.h> | 8 #include <sys/time.h> |
| 9 #include <time.h> | 9 #include <time.h> |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "base/string_split.h" | 21 #include "base/string_split.h" |
| 22 #include "base/string_util.h" | 22 #include "base/string_util.h" |
| 23 #include "base/third_party/xdg_mime/xdgmime.h" | 23 #include "base/third_party/xdg_mime/xdgmime.h" |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 class IconTheme; | 27 class IconTheme; |
| 28 | 28 |
| 29 class MimeUtilConstants { | 29 class MimeUtilConstants { |
| 30 public: | 30 public: |
| 31 static MimeUtilConstants* GetInstance() { |
| 32 return Singleton<MimeUtilConstants>::get(); |
| 33 } |
| 31 | 34 |
| 32 // In seconds, specified by icon theme specs. | 35 // In seconds, specified by icon theme specs. |
| 33 const int kUpdateInterval; | 36 const int kUpdateInterval; |
| 34 | 37 |
| 35 // Store icon directories and their mtimes. | 38 // Store icon directories and their mtimes. |
| 36 std::map<FilePath, int>* icon_dirs_; | 39 std::map<FilePath, int>* icon_dirs_; |
| 37 | 40 |
| 38 // Store icon formats. | 41 // Store icon formats. |
| 39 std::vector<std::string> icon_formats_; | 42 std::vector<std::string> icon_formats_; |
| 40 | 43 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 }; | 153 }; |
| 151 | 154 |
| 152 IconTheme::IconTheme(const std::string& name) | 155 IconTheme::IconTheme(const std::string& name) |
| 153 : index_theme_loaded_(false), | 156 : index_theme_loaded_(false), |
| 154 info_array_(NULL) { | 157 info_array_(NULL) { |
| 155 // Iterate on all icon directories to find directories of the specified | 158 // Iterate on all icon directories to find directories of the specified |
| 156 // theme and load the first encountered index.theme. | 159 // theme and load the first encountered index.theme. |
| 157 std::map<FilePath, int>::iterator iter; | 160 std::map<FilePath, int>::iterator iter; |
| 158 FilePath theme_path; | 161 FilePath theme_path; |
| 159 std::map<FilePath, int>* icon_dirs = | 162 std::map<FilePath, int>* icon_dirs = |
| 160 Singleton<MimeUtilConstants>::get()->icon_dirs_; | 163 MimeUtilConstants::GetInstance()->icon_dirs_; |
| 161 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { | 164 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { |
| 162 theme_path = iter->first.Append(name); | 165 theme_path = iter->first.Append(name); |
| 163 if (!file_util::DirectoryExists(theme_path)) | 166 if (!file_util::DirectoryExists(theme_path)) |
| 164 continue; | 167 continue; |
| 165 FilePath theme_index = theme_path.Append("index.theme"); | 168 FilePath theme_index = theme_path.Append("index.theme"); |
| 166 if (!index_theme_loaded_ && file_util::PathExists(theme_index)) { | 169 if (!index_theme_loaded_ && file_util::PathExists(theme_index)) { |
| 167 if (!LoadIndexTheme(theme_index)) | 170 if (!LoadIndexTheme(theme_index)) |
| 168 return; | 171 return; |
| 169 index_theme_loaded_ = true; | 172 index_theme_loaded_ = true; |
| 170 } | 173 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 // Inheriting from itself means the theme is buggy but we shouldn't crash. | 214 // Inheriting from itself means the theme is buggy but we shouldn't crash. |
| 212 if (theme && theme != this) | 215 if (theme && theme != this) |
| 213 return theme->GetIconPath(icon_name, size, inherits); | 216 return theme->GetIconPath(icon_name, size, inherits); |
| 214 else | 217 else |
| 215 return FilePath(); | 218 return FilePath(); |
| 216 } | 219 } |
| 217 | 220 |
| 218 IconTheme* IconTheme::LoadTheme(const std::string& theme_name) { | 221 IconTheme* IconTheme::LoadTheme(const std::string& theme_name) { |
| 219 scoped_ptr<IconTheme> theme; | 222 scoped_ptr<IconTheme> theme; |
| 220 std::map<std::string, IconTheme*>* icon_themes = | 223 std::map<std::string, IconTheme*>* icon_themes = |
| 221 Singleton<MimeUtilConstants>::get()->icon_themes_; | 224 MimeUtilConstants::GetInstance()->icon_themes_; |
| 222 if (icon_themes->find(theme_name) != icon_themes->end()) { | 225 if (icon_themes->find(theme_name) != icon_themes->end()) { |
| 223 theme.reset((*icon_themes)[theme_name]); | 226 theme.reset((*icon_themes)[theme_name]); |
| 224 } else { | 227 } else { |
| 225 theme.reset(new IconTheme(theme_name)); | 228 theme.reset(new IconTheme(theme_name)); |
| 226 if (!theme->IsValid()) | 229 if (!theme->IsValid()) |
| 227 theme.reset(); | 230 theme.reset(); |
| 228 (*icon_themes)[theme_name] = theme.get(); | 231 (*icon_themes)[theme_name] = theme.get(); |
| 229 } | 232 } |
| 230 return theme.release(); | 233 return theme.release(); |
| 231 } | 234 } |
| 232 | 235 |
| 233 FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name, | 236 FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name, |
| 234 const std::string& subdir) { | 237 const std::string& subdir) { |
| 235 FilePath icon_path; | 238 FilePath icon_path; |
| 236 std::list<FilePath>::iterator dir_iter; | 239 std::list<FilePath>::iterator dir_iter; |
| 237 std::vector<std::string>* icon_formats = | 240 std::vector<std::string>* icon_formats = |
| 238 &Singleton<MimeUtilConstants>::get()->icon_formats_; | 241 &MimeUtilConstants::GetInstance()->icon_formats_; |
| 239 for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) { | 242 for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) { |
| 240 for (size_t i = 0; i < icon_formats->size(); ++i) { | 243 for (size_t i = 0; i < icon_formats->size(); ++i) { |
| 241 icon_path = dir_iter->Append(subdir); | 244 icon_path = dir_iter->Append(subdir); |
| 242 icon_path = icon_path.Append(icon_name + (*icon_formats)[i]); | 245 icon_path = icon_path.Append(icon_name + (*icon_formats)[i]); |
| 243 if (file_util::PathExists(icon_path)) | 246 if (file_util::PathExists(icon_path)) |
| 244 return icon_path; | 247 return icon_path; |
| 245 } | 248 } |
| 246 } | 249 } |
| 247 return FilePath(); | 250 return FilePath(); |
| 248 } | 251 } |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 } | 379 } |
| 377 subdirs_[dir] = num++; | 380 subdirs_[dir] = num++; |
| 378 info_array_ = new SubDirInfo[num]; | 381 info_array_ = new SubDirInfo[num]; |
| 379 return true; | 382 return true; |
| 380 } | 383 } |
| 381 | 384 |
| 382 // Make sure |dir| exists and add it to the list of icon directories. | 385 // Make sure |dir| exists and add it to the list of icon directories. |
| 383 void TryAddIconDir(const FilePath& dir) { | 386 void TryAddIconDir(const FilePath& dir) { |
| 384 if (!file_util::DirectoryExists(dir)) | 387 if (!file_util::DirectoryExists(dir)) |
| 385 return; | 388 return; |
| 386 (*Singleton<MimeUtilConstants>::get()->icon_dirs_)[dir] = 0; | 389 (*MimeUtilConstants::GetInstance()->icon_dirs_)[dir] = 0; |
| 387 } | 390 } |
| 388 | 391 |
| 389 // For a xdg directory |dir|, add the appropriate icon sub-directories. | 392 // For a xdg directory |dir|, add the appropriate icon sub-directories. |
| 390 void AddXDGDataDir(const FilePath& dir) { | 393 void AddXDGDataDir(const FilePath& dir) { |
| 391 if (!file_util::DirectoryExists(dir)) | 394 if (!file_util::DirectoryExists(dir)) |
| 392 return; | 395 return; |
| 393 TryAddIconDir(dir.Append("icons")); | 396 TryAddIconDir(dir.Append("icons")); |
| 394 TryAddIconDir(dir.Append("pixmaps")); | 397 TryAddIconDir(dir.Append("pixmaps")); |
| 395 } | 398 } |
| 396 | 399 |
| 397 // Add all the xdg icon directories. | 400 // Add all the xdg icon directories. |
| 398 void InitIconDir() { | 401 void InitIconDir() { |
| 399 Singleton<MimeUtilConstants>::get()->icon_dirs_->clear(); | 402 MimeUtilConstants::GetInstance()->icon_dirs_->clear(); |
| 400 FilePath home = file_util::GetHomeDir(); | 403 FilePath home = file_util::GetHomeDir(); |
| 401 if (!home.empty()) { | 404 if (!home.empty()) { |
| 402 FilePath legacy_data_dir(home); | 405 FilePath legacy_data_dir(home); |
| 403 legacy_data_dir = legacy_data_dir.AppendASCII(".icons"); | 406 legacy_data_dir = legacy_data_dir.AppendASCII(".icons"); |
| 404 if (file_util::DirectoryExists(legacy_data_dir)) | 407 if (file_util::DirectoryExists(legacy_data_dir)) |
| 405 TryAddIconDir(legacy_data_dir); | 408 TryAddIconDir(legacy_data_dir); |
| 406 } | 409 } |
| 407 const char* env = getenv("XDG_DATA_HOME"); | 410 const char* env = getenv("XDG_DATA_HOME"); |
| 408 if (env) { | 411 if (env) { |
| 409 AddXDGDataDir(FilePath(env)); | 412 AddXDGDataDir(FilePath(env)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 428 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); | 431 AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); |
| 429 } | 432 } |
| 430 } | 433 } |
| 431 | 434 |
| 432 // Per xdg theme spec, we should check the icon directories every so often for | 435 // Per xdg theme spec, we should check the icon directories every so often for |
| 433 // newly added icons. This isn't quite right. | 436 // newly added icons. This isn't quite right. |
| 434 void EnsureUpdated() { | 437 void EnsureUpdated() { |
| 435 struct timeval t; | 438 struct timeval t; |
| 436 gettimeofday(&t, NULL); | 439 gettimeofday(&t, NULL); |
| 437 time_t now = t.tv_sec; | 440 time_t now = t.tv_sec; |
| 438 MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get(); | 441 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); |
| 439 | 442 |
| 440 if (constants->last_check_time_ == 0) { | 443 if (constants->last_check_time_ == 0) { |
| 441 constants->icon_dirs_ = new std::map<FilePath, int>; | 444 constants->icon_dirs_ = new std::map<FilePath, int>; |
| 442 constants->icon_themes_ = new std::map<std::string, IconTheme*>; | 445 constants->icon_themes_ = new std::map<std::string, IconTheme*>; |
| 443 InitIconDir(); | 446 InitIconDir(); |
| 444 constants->last_check_time_ = now; | 447 constants->last_check_time_ = now; |
| 445 } else { | 448 } else { |
| 446 // TODO(thestig): something changed. start over. Upstream fix to Google | 449 // TODO(thestig): something changed. start over. Upstream fix to Google |
| 447 // Gadgets for Linux. | 450 // Gadgets for Linux. |
| 448 if (now > constants->last_check_time_ + constants->kUpdateInterval) { | 451 if (now > constants->last_check_time_ + constants->kUpdateInterval) { |
| 449 } | 452 } |
| 450 } | 453 } |
| 451 } | 454 } |
| 452 | 455 |
| 453 // Find a fallback icon if we cannot find it in the default theme. | 456 // Find a fallback icon if we cannot find it in the default theme. |
| 454 FilePath LookupFallbackIcon(const std::string& icon_name) { | 457 FilePath LookupFallbackIcon(const std::string& icon_name) { |
| 455 FilePath icon; | 458 FilePath icon; |
| 456 MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get(); | 459 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); |
| 457 std::map<FilePath, int>::iterator iter; | 460 std::map<FilePath, int>::iterator iter; |
| 458 std::map<FilePath, int>* icon_dirs = constants->icon_dirs_; | 461 std::map<FilePath, int>* icon_dirs = constants->icon_dirs_; |
| 459 std::vector<std::string>* icon_formats = &constants->icon_formats_; | 462 std::vector<std::string>* icon_formats = &constants->icon_formats_; |
| 460 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { | 463 for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { |
| 461 for (size_t i = 0; i < icon_formats->size(); ++i) { | 464 for (size_t i = 0; i < icon_formats->size(); ++i) { |
| 462 icon = iter->first.Append(icon_name + (*icon_formats)[i]); | 465 icon = iter->first.Append(icon_name + (*icon_formats)[i]); |
| 463 if (file_util::PathExists(icon)) | 466 if (file_util::PathExists(icon)) |
| 464 return icon; | 467 return icon; |
| 465 } | 468 } |
| 466 } | 469 } |
| 467 return FilePath(); | 470 return FilePath(); |
| 468 } | 471 } |
| 469 | 472 |
| 470 // Initialize the list of default themes. | 473 // Initialize the list of default themes. |
| 471 void InitDefaultThemes() { | 474 void InitDefaultThemes() { |
| 472 IconTheme** default_themes = | 475 IconTheme** default_themes = |
| 473 Singleton<MimeUtilConstants>::get()->default_themes_; | 476 MimeUtilConstants::GetInstance()->default_themes_; |
| 474 | 477 |
| 475 char* env = getenv("KDE_FULL_SESSION"); | 478 char* env = getenv("KDE_FULL_SESSION"); |
| 476 if (env) { | 479 if (env) { |
| 477 // KDE | 480 // KDE |
| 478 std::string kde_default_theme; | 481 std::string kde_default_theme; |
| 479 std::string kde_fallback_theme; | 482 std::string kde_fallback_theme; |
| 480 | 483 |
| 481 // TODO(thestig): Figure out how to get the current icon theme on KDE. | 484 // TODO(thestig): Figure out how to get the current icon theme on KDE. |
| 482 // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme. | 485 // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme. |
| 483 default_themes[0] = NULL; | 486 default_themes[0] = NULL; |
| 484 | 487 |
| 485 // Try some reasonable defaults for KDE. | 488 // Try some reasonable defaults for KDE. |
| 486 env = getenv("KDE_SESSION_VERSION"); | 489 env = getenv("KDE_SESSION_VERSION"); |
| 487 if (!env || env[0] != '4') { | 490 if (!env || env[0] != '4') { |
| 488 // KDE 3 | 491 // KDE 3 |
| 489 kde_default_theme = "default.kde"; | 492 kde_default_theme = "default.kde"; |
| 490 kde_fallback_theme = "crystalsvg"; | 493 kde_fallback_theme = "crystalsvg"; |
| 491 } else { | 494 } else { |
| 492 // KDE 4 | 495 // KDE 4 |
| 493 kde_default_theme = "default.kde4"; | 496 kde_default_theme = "default.kde4"; |
| 494 kde_fallback_theme = "oxygen"; | 497 kde_fallback_theme = "oxygen"; |
| 495 } | 498 } |
| 496 default_themes[1] = IconTheme::LoadTheme(kde_default_theme); | 499 default_themes[1] = IconTheme::LoadTheme(kde_default_theme); |
| 497 default_themes[2] = IconTheme::LoadTheme(kde_fallback_theme); | 500 default_themes[2] = IconTheme::LoadTheme(kde_fallback_theme); |
| 498 } else { | 501 } else { |
| 499 // Assume it's Gnome and use GTK to figure out the theme. | 502 // Assume it's Gnome and use GTK to figure out the theme. |
| 500 default_themes[1] = IconTheme::LoadTheme( | 503 default_themes[1] = IconTheme::LoadTheme( |
| 501 Singleton<MimeUtilConstants>::get()->gtk_theme_name_); | 504 MimeUtilConstants::GetInstance()->gtk_theme_name_); |
| 502 default_themes[2] = IconTheme::LoadTheme("gnome"); | 505 default_themes[2] = IconTheme::LoadTheme("gnome"); |
| 503 } | 506 } |
| 504 // hicolor needs to be last per icon theme spec. | 507 // hicolor needs to be last per icon theme spec. |
| 505 default_themes[3] = IconTheme::LoadTheme("hicolor"); | 508 default_themes[3] = IconTheme::LoadTheme("hicolor"); |
| 506 | 509 |
| 507 for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) { | 510 for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) { |
| 508 if (default_themes[i] == NULL) | 511 if (default_themes[i] == NULL) |
| 509 continue; | 512 continue; |
| 510 // NULL out duplicate pointers. | 513 // NULL out duplicate pointers. |
| 511 for (size_t j = i + 1; j < MimeUtilConstants::kDefaultThemeNum; j++) { | 514 for (size_t j = i + 1; j < MimeUtilConstants::kDefaultThemeNum; j++) { |
| 512 if (default_themes[j] == default_themes[i]) | 515 if (default_themes[j] == default_themes[i]) |
| 513 default_themes[j] = NULL; | 516 default_themes[j] = NULL; |
| 514 } | 517 } |
| 515 } | 518 } |
| 516 } | 519 } |
| 517 | 520 |
| 518 // Try to find an icon with the name |icon_name| that's |size| pixels. | 521 // Try to find an icon with the name |icon_name| that's |size| pixels. |
| 519 FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) { | 522 FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) { |
| 520 EnsureUpdated(); | 523 EnsureUpdated(); |
| 521 MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get(); | 524 MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); |
| 522 std::map<std::string, IconTheme*>* icon_themes = constants->icon_themes_; | 525 std::map<std::string, IconTheme*>* icon_themes = constants->icon_themes_; |
| 523 if (icon_themes->size() == 0) | 526 if (icon_themes->size() == 0) |
| 524 InitDefaultThemes(); | 527 InitDefaultThemes(); |
| 525 | 528 |
| 526 FilePath icon_path; | 529 FilePath icon_path; |
| 527 IconTheme** default_themes = constants->default_themes_; | 530 IconTheme** default_themes = constants->default_themes_; |
| 528 for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) { | 531 for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) { |
| 529 if (default_themes[i]) { | 532 if (default_themes[i]) { |
| 530 icon_path = default_themes[i]->GetIconPath(icon_name, size, true); | 533 icon_path = default_themes[i]->GetIconPath(icon_name, size, true); |
| 531 if (!icon_path.empty()) | 534 if (!icon_path.empty()) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 551 } | 554 } |
| 552 | 555 |
| 553 std::string GetDataMimeType(const std::string& data) { | 556 std::string GetDataMimeType(const std::string& data) { |
| 554 return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL); | 557 return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL); |
| 555 } | 558 } |
| 556 | 559 |
| 557 void DetectGtkTheme() { | 560 void DetectGtkTheme() { |
| 558 // If the theme name is already loaded, do nothing. Chrome doesn't respond | 561 // If the theme name is already loaded, do nothing. Chrome doesn't respond |
| 559 // to changes in the system theme, so we never need to set this more than | 562 // to changes in the system theme, so we never need to set this more than |
| 560 // once. | 563 // once. |
| 561 if (!Singleton<MimeUtilConstants>::get()->gtk_theme_name_.empty()) | 564 if (!MimeUtilConstants::GetInstance()->gtk_theme_name_.empty()) |
| 562 return; | 565 return; |
| 563 | 566 |
| 564 // We should only be called on the UI thread. | 567 // We should only be called on the UI thread. |
| 565 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); | 568 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); |
| 566 | 569 |
| 567 gchar* gtk_theme_name; | 570 gchar* gtk_theme_name; |
| 568 g_object_get(gtk_settings_get_default(), | 571 g_object_get(gtk_settings_get_default(), |
| 569 "gtk-icon-theme-name", | 572 "gtk-icon-theme-name", |
| 570 >k_theme_name, NULL); | 573 >k_theme_name, NULL); |
| 571 Singleton<MimeUtilConstants>::get()->gtk_theme_name_.assign(gtk_theme_name); | 574 MimeUtilConstants::GetInstance()->gtk_theme_name_.assign(gtk_theme_name); |
| 572 g_free(gtk_theme_name); | 575 g_free(gtk_theme_name); |
| 573 } | 576 } |
| 574 | 577 |
| 575 FilePath GetMimeIcon(const std::string& mime_type, size_t size) { | 578 FilePath GetMimeIcon(const std::string& mime_type, size_t size) { |
| 576 std::vector<std::string> icon_names; | 579 std::vector<std::string> icon_names; |
| 577 std::string icon_name; | 580 std::string icon_name; |
| 578 FilePath icon_file; | 581 FilePath icon_file; |
| 579 | 582 |
| 580 const char* icon = xdg_mime_get_icon(mime_type.c_str()); | 583 const char* icon = xdg_mime_get_icon(mime_type.c_str()); |
| 581 icon_name = std::string(icon ? icon : ""); | 584 icon_name = std::string(icon ? icon : ""); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 611 } else { | 614 } else { |
| 612 icon_file = LookupIconInDefaultTheme(icon_names[i], size); | 615 icon_file = LookupIconInDefaultTheme(icon_names[i], size); |
| 613 if (!icon_file.empty()) | 616 if (!icon_file.empty()) |
| 614 return icon_file; | 617 return icon_file; |
| 615 } | 618 } |
| 616 } | 619 } |
| 617 return FilePath(); | 620 return FilePath(); |
| 618 } | 621 } |
| 619 | 622 |
| 620 } // namespace mime_util | 623 } // namespace mime_util |
| OLD | NEW |