Index: chrome/browser/ui/libgtk2ui/app_indicator_icon.cc |
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc |
index 757052e1d0e064dbfc02a242f1cd20ac497dc6a3..671ed16742315f68ab15e5316752454f6b803d78 100644 |
--- a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc |
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc |
@@ -8,8 +8,11 @@ |
#include <dlfcn.h> |
#include "base/bind.h" |
+#include "base/environment.h" |
#include "base/file_util.h" |
+#include "base/md5.h" |
#include "base/memory/ref_counted_memory.h" |
+#include "base/nix/xdg_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/threading/sequenced_worker_pool.h" |
@@ -121,9 +124,56 @@ void EnsureMethodsLoaded() { |
dlsym(indicator_lib, "app_indicator_set_icon_theme_path")); |
} |
-base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr, |
+// Returns whether a temporary directory should be created for each app |
+// indicator image. |
+bool ShouldCreateTempDirectoryPerImage(bool using_kde4) { |
+ // Create a new temporary directory for each image on Unity since using a |
+ // single temporary directory seems to have issues when changing icons in |
+ // quick succession. |
+ return !using_kde4; |
+} |
+ |
+// Returns the subdirectory of |temp_dir| in which the app indicator image |
+// should be saved. |
+base::FilePath GetImageDirectoryPath(bool using_kde4, |
+ const base::FilePath& temp_dir) { |
+ // On KDE4, an image located in a directory ending with |
+ // "icons/hicolor/16x16/apps" can be used as the app indicator image because |
+ // "/usr/share/icons/hicolor/16x16/apps" exists. |
+ return using_kde4 ? |
+ temp_dir.AppendASCII("icons").AppendASCII("hicolor").AppendASCII("16x16"). |
+ AppendASCII("apps") : |
+ temp_dir; |
+} |
+ |
+std::string GetImageFileNameForKDE4( |
+ const scoped_refptr<base::RefCountedMemory>& png_data) { |
+ // On KDE4, the name of the image file for each different looking bitmap must |
+ // be unique. It must also be unique across runs of Chrome. |
+ base::MD5Digest digest; |
+ base::MD5Sum(png_data->front_as<char>(), png_data->size(), &digest); |
+ return base::StringPrintf("chrome_app_indicator_%s.png", |
+ base::MD5DigestToBase16(digest).c_str()); |
+} |
+ |
+std::string GetImageFileNameForNonKDE4(int icon_change_count, |
+ const std::string& id) { |
+ return base::StringPrintf("%s_%d.png", id.c_str(), icon_change_count); |
+} |
+ |
+// Returns the "icon theme path" given the file path of the app indicator image. |
+std::string GetIconThemePath(bool using_kde4, |
+ const base::FilePath& image_path) { |
+ return using_kde4 ? |
+ image_path.DirName().DirName().DirName().DirName().value() : |
+ image_path.DirName().value(); |
+} |
+ |
+base::FilePath CreateTempImageFile(bool using_kde4, |
+ gfx::ImageSkia* image_ptr, |
int icon_change_count, |
- std::string id) { |
+ std::string id, |
+ const base::FilePath& previous_file_path) { |
scoped_ptr<gfx::ImageSkia> image(image_ptr); |
scoped_refptr<base::RefCountedMemory> png_data = |
@@ -134,16 +184,25 @@ base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr, |
return base::FilePath(); |
} |
- base::FilePath temp_dir; |
base::FilePath new_file_path; |
+ if (previous_file_path.empty() || |
+ ShouldCreateTempDirectoryPerImage(using_kde4)) { |
+ base::FilePath tmp_dir; |
+ if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &tmp_dir)) |
+ return base::FilePath(); |
+ new_file_path = GetImageDirectoryPath(using_kde4, tmp_dir); |
+ if (new_file_path != tmp_dir) { |
+ if (!base::CreateDirectory(new_file_path)) |
+ return base::FilePath(); |
+ } |
+ } else { |
+ new_file_path = previous_file_path.DirName(); |
+ } |
+ |
+ new_file_path = new_file_path.Append(using_kde4 ? |
+ GetImageFileNameForKDE4(png_data) : |
+ GetImageFileNameForNonKDE4(icon_change_count, id)); |
- // Create a new temporary directory for each image since using a single |
- // temporary directory seems to have issues when changing icons in quick |
- // succession. |
- if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_dir)) |
- return base::FilePath(); |
- new_file_path = |
- temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count)); |
int bytes_written = |
base::WriteFile(new_file_path, |
png_data->front_as<char>(), png_data->size()); |
@@ -153,10 +212,10 @@ base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr, |
return new_file_path; |
} |
-void DeleteTempImagePath(const base::FilePath& icon_file_path) { |
- if (icon_file_path.empty()) |
+void DeleteTempDirectory(const base::FilePath& dir_path) { |
+ if (dir_path.empty()) |
return; |
- base::DeleteFile(icon_file_path, true); |
+ base::DeleteFile(dir_path, true); |
} |
} // namespace |
@@ -167,10 +226,15 @@ AppIndicatorIcon::AppIndicatorIcon(std::string id, |
const gfx::ImageSkia& image, |
const base::string16& tool_tip) |
: id_(id), |
+ using_kde4_(false), |
icon_(NULL), |
menu_model_(NULL), |
icon_change_count_(0), |
weak_factory_(this) { |
+ scoped_ptr<base::Environment> env(base::Environment::Create()); |
+ using_kde4_ = base::nix::GetDesktopEnvironment(env.get()) == |
+ base::nix::DESKTOP_ENVIRONMENT_KDE4; |
+ |
EnsureMethodsLoaded(); |
tool_tip_ = base::UTF16ToUTF8(tool_tip); |
SetImage(image); |
@@ -181,7 +245,7 @@ AppIndicatorIcon::~AppIndicatorIcon() { |
g_object_unref(icon_); |
content::BrowserThread::GetBlockingPool()->PostTask( |
FROM_HERE, |
- base::Bind(&DeleteTempImagePath, icon_file_path_.DirName())); |
+ base::Bind(&DeleteTempDirectory, icon_file_path_.DirName())); |
} |
} |
@@ -206,9 +270,11 @@ void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) { |
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(), |
FROM_HERE, |
base::Bind(&CreateTempImageFile, |
+ using_kde4_, |
safe_image.release(), |
icon_change_count_, |
- id_), |
+ id_, |
+ icon_file_path_), |
base::Bind(&AppIndicatorIcon::SetImageFromFile, |
weak_factory_.GetWeakPtr())); |
} |
@@ -250,7 +316,7 @@ void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) { |
std::string icon_name = |
icon_file_path_.BaseName().RemoveExtension().value(); |
- std::string icon_dir = icon_file_path_.DirName().value(); |
+ std::string icon_dir = GetIconThemePath(using_kde4_, icon_file_path); |
if (!icon_) { |
icon_ = |
app_indicator_new_with_path(id_.c_str(), |
@@ -265,10 +331,12 @@ void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) { |
app_indicator_set_icon_theme_path(icon_, icon_dir.c_str()); |
app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon"); |
- // Delete previous icon directory. |
- content::BrowserThread::GetBlockingPool()->PostTask( |
- FROM_HERE, |
- base::Bind(&DeleteTempImagePath, old_path.DirName())); |
+ if (ShouldCreateTempDirectoryPerImage(using_kde4_)) { |
+ // Delete previous icon directory. |
+ content::BrowserThread::GetBlockingPool()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DeleteTempDirectory, old_path.DirName())); |
+ } |
} |
} |