Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: chrome/browser/ui/libgtk2ui/app_indicator_icon.cc

Issue 309103002: Make the system tray icons display when using KDE4 and plasma (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/libgtk2ui/app_indicator_icon.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/ui/libgtk2ui/app_indicator_icon.h" 5 #include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 #include <dlfcn.h> 8 #include <dlfcn.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/environment.h"
11 #include "base/file_util.h" 12 #include "base/file_util.h"
13 #include "base/md5.h"
12 #include "base/memory/ref_counted_memory.h" 14 #include "base/memory/ref_counted_memory.h"
15 #include "base/nix/xdg_util.h"
13 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" 19 #include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h"
17 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/browser_thread.h"
18 #include "ui/base/models/menu_model.h" 21 #include "ui/base/models/menu_model.h"
19 #include "ui/gfx/image/image.h" 22 #include "ui/gfx/image/image.h"
20 #include "ui/gfx/image/image_skia.h" 23 #include "ui/gfx/image/image_skia.h"
21 24
22 namespace { 25 namespace {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 117
115 app_indicator_set_icon_full = 118 app_indicator_set_icon_full =
116 reinterpret_cast<app_indicator_set_icon_full_func>( 119 reinterpret_cast<app_indicator_set_icon_full_func>(
117 dlsym(indicator_lib, "app_indicator_set_icon_full")); 120 dlsym(indicator_lib, "app_indicator_set_icon_full"));
118 121
119 app_indicator_set_icon_theme_path = 122 app_indicator_set_icon_theme_path =
120 reinterpret_cast<app_indicator_set_icon_theme_path_func>( 123 reinterpret_cast<app_indicator_set_icon_theme_path_func>(
121 dlsym(indicator_lib, "app_indicator_set_icon_theme_path")); 124 dlsym(indicator_lib, "app_indicator_set_icon_theme_path"));
122 } 125 }
123 126
124 base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr, 127 // Returns whether a temporary directory should be created for each app
128 // indicator image.
129 bool ShouldCreateTempDirectoryPerImage(bool using_kde4) {
130 // Create a new temporary directory for each image on Unity since using a
131 // single temporary directory seems to have issues when changing icons in
132 // quick succession.
133 return !using_kde4;
pkotwicz 2014/06/02 18:41:58 Creating a temporary directory per icon causes pro
134 }
135
136 // Returns the subdirectory of |temp_dir| in which the app indicator image
137 // should be saved.
138 base::FilePath GetImageDirectoryPath(bool using_kde4,
139 const base::FilePath& temp_dir) {
140 // On KDE4, an image located in a directory ending with
141 // "icons/hicolor/16x16/apps" can be used as the app indicator image because
142 // "/usr/share/icons/hicolor/16x16/apps" exists.
pkotwicz 2014/06/02 18:41:58 KDE5 (which uses QIconLoader instead of KIconLoade
143 return using_kde4 ?
144 temp_dir.AppendASCII("icons").AppendASCII("hicolor").AppendASCII("16x16").
145 AppendASCII("apps") :
146 temp_dir;
147 }
148
149 std::string GetImageFileNameForKDE4(
150 const scoped_refptr<base::RefCountedMemory>& png_data) {
pkotwicz 2014/06/02 18:41:58 sni-qt (https://launchpad.net/sni-qt) seems to do
151 // On KDE4, the name of the image file must be unique accross runs of
152 // Chrome.
Elliot Glaysher 2014/06/02 20:06:04 Is this comment correct? The following seems to ma
153 base::MD5Digest digest;
154 base::MD5Sum(png_data->front_as<char>(), png_data->size(), &digest);
155 return base::StringPrintf("chrome_app_indicator_%s.png",
156 base::MD5DigestToBase16(digest).c_str());
157 }
158
159 std::string GetImageFileNameForNonKDE4(int icon_change_count,
160 const std::string& id) {
161 return base::StringPrintf("%s_%d.png", id.c_str(), icon_change_count);
162 }
163
164 // Returns the "icon theme path" given the file path of the app indicator image.
165 std::string GetIconThemePath(bool using_kde4,
166 const base::FilePath& image_path) {
167 return using_kde4 ?
168 image_path.DirName().DirName().DirName().DirName().value() :
169 image_path.DirName().value();
170 }
171
172 base::FilePath CreateTempImageFile(bool using_kde4,
173 gfx::ImageSkia* image_ptr,
125 int icon_change_count, 174 int icon_change_count,
126 std::string id) { 175 std::string id,
176 const base::FilePath& previous_file_path) {
127 scoped_ptr<gfx::ImageSkia> image(image_ptr); 177 scoped_ptr<gfx::ImageSkia> image(image_ptr);
128 178
129 scoped_refptr<base::RefCountedMemory> png_data = 179 scoped_refptr<base::RefCountedMemory> png_data =
130 gfx::Image(*image.get()).As1xPNGBytes(); 180 gfx::Image(*image.get()).As1xPNGBytes();
131 if (png_data->size() == 0) { 181 if (png_data->size() == 0) {
132 // If the bitmap could not be encoded to PNG format, skip it. 182 // If the bitmap could not be encoded to PNG format, skip it.
133 LOG(WARNING) << "Could not encode icon"; 183 LOG(WARNING) << "Could not encode icon";
134 return base::FilePath(); 184 return base::FilePath();
135 } 185 }
136 186
137 base::FilePath temp_dir;
138 base::FilePath new_file_path; 187 base::FilePath new_file_path;
188 if (previous_file_path.empty() ||
189 ShouldCreateTempDirectoryPerImage(using_kde4)) {
190 base::FilePath tmp_dir;
191 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &tmp_dir))
192 return base::FilePath();
193 new_file_path = GetImageDirectoryPath(using_kde4, tmp_dir);
194 if (new_file_path != tmp_dir) {
195 if (!base::CreateDirectory(new_file_path))
196 return base::FilePath();
197 }
198 } else {
199 new_file_path = previous_file_path.DirName();
200 }
139 201
140 // Create a new temporary directory for each image since using a single 202 new_file_path = new_file_path.Append(using_kde4 ?
141 // temporary directory seems to have issues when changing icons in quick 203 GetImageFileNameForKDE4(png_data) :
142 // succession. 204 GetImageFileNameForNonKDE4(icon_change_count, id));
143 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_dir)) 205
144 return base::FilePath();
145 new_file_path =
146 temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count));
147 int bytes_written = 206 int bytes_written =
148 base::WriteFile(new_file_path, 207 base::WriteFile(new_file_path,
149 png_data->front_as<char>(), png_data->size()); 208 png_data->front_as<char>(), png_data->size());
150 209
151 if (bytes_written != static_cast<int>(png_data->size())) 210 if (bytes_written != static_cast<int>(png_data->size()))
152 return base::FilePath(); 211 return base::FilePath();
153 return new_file_path; 212 return new_file_path;
154 } 213 }
155 214
156 void DeleteTempImagePath(const base::FilePath& icon_file_path) { 215 void DeleteTempDirectory(const base::FilePath& dir_path) {
157 if (icon_file_path.empty()) 216 if (dir_path.empty())
158 return; 217 return;
159 base::DeleteFile(icon_file_path, true); 218 base::DeleteFile(dir_path, true);
160 } 219 }
161 220
162 } // namespace 221 } // namespace
163 222
164 namespace libgtk2ui { 223 namespace libgtk2ui {
165 224
166 AppIndicatorIcon::AppIndicatorIcon(std::string id, 225 AppIndicatorIcon::AppIndicatorIcon(std::string id,
167 const gfx::ImageSkia& image, 226 const gfx::ImageSkia& image,
168 const base::string16& tool_tip) 227 const base::string16& tool_tip)
169 : id_(id), 228 : id_(id),
229 using_kde4_(false),
170 icon_(NULL), 230 icon_(NULL),
171 menu_model_(NULL), 231 menu_model_(NULL),
172 icon_change_count_(0), 232 icon_change_count_(0),
173 weak_factory_(this) { 233 weak_factory_(this) {
234 scoped_ptr<base::Environment> env(base::Environment::Create());
235 using_kde4_ = base::nix::GetDesktopEnvironment(env.get()) ==
236 base::nix::DESKTOP_ENVIRONMENT_KDE4;
237
174 EnsureMethodsLoaded(); 238 EnsureMethodsLoaded();
175 tool_tip_ = base::UTF16ToUTF8(tool_tip); 239 tool_tip_ = base::UTF16ToUTF8(tool_tip);
176 SetImage(image); 240 SetImage(image);
177 } 241 }
178 AppIndicatorIcon::~AppIndicatorIcon() { 242 AppIndicatorIcon::~AppIndicatorIcon() {
179 if (icon_) { 243 if (icon_) {
180 app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE); 244 app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
181 g_object_unref(icon_); 245 g_object_unref(icon_);
182 content::BrowserThread::GetBlockingPool()->PostTask( 246 content::BrowserThread::GetBlockingPool()->PostTask(
183 FROM_HERE, 247 FROM_HERE,
184 base::Bind(&DeleteTempImagePath, icon_file_path_.DirName())); 248 base::Bind(&DeleteTempDirectory, icon_file_path_.DirName()));
185 } 249 }
186 } 250 }
187 251
188 // static 252 // static
189 bool AppIndicatorIcon::CouldOpen() { 253 bool AppIndicatorIcon::CouldOpen() {
190 EnsureMethodsLoaded(); 254 EnsureMethodsLoaded();
191 return g_opened; 255 return g_opened;
192 } 256 }
193 257
194 void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) { 258 void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) {
195 if (!g_opened) 259 if (!g_opened)
196 return; 260 return;
197 261
198 ++icon_change_count_; 262 ++icon_change_count_;
199 263
200 // We create a deep copy of the image since it may have been freed by the time 264 // We create a deep copy of the image since it may have been freed by the time
201 // it's accessed in the other thread. 265 // it's accessed in the other thread.
202 scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy()); 266 scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy());
203 base::PostTaskAndReplyWithResult( 267 base::PostTaskAndReplyWithResult(
204 content::BrowserThread::GetBlockingPool() 268 content::BrowserThread::GetBlockingPool()
205 ->GetTaskRunnerWithShutdownBehavior( 269 ->GetTaskRunnerWithShutdownBehavior(
206 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(), 270 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
207 FROM_HERE, 271 FROM_HERE,
208 base::Bind(&CreateTempImageFile, 272 base::Bind(&CreateTempImageFile,
273 using_kde4_,
209 safe_image.release(), 274 safe_image.release(),
210 icon_change_count_, 275 icon_change_count_,
211 id_), 276 id_,
277 icon_file_path_),
212 base::Bind(&AppIndicatorIcon::SetImageFromFile, 278 base::Bind(&AppIndicatorIcon::SetImageFromFile,
213 weak_factory_.GetWeakPtr())); 279 weak_factory_.GetWeakPtr()));
214 } 280 }
215 281
216 void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) { 282 void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
217 // Ignore pressed images, since the standard on Linux is to not highlight 283 // Ignore pressed images, since the standard on Linux is to not highlight
218 // pressed status icons. 284 // pressed status icons.
219 } 285 }
220 286
221 void AppIndicatorIcon::SetToolTip(const base::string16& tool_tip) { 287 void AppIndicatorIcon::SetToolTip(const base::string16& tool_tip) {
(...skipping 21 matching lines...) Expand all
243 void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) { 309 void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) {
244 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 310 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
245 if (icon_file_path.empty()) 311 if (icon_file_path.empty())
246 return; 312 return;
247 313
248 base::FilePath old_path = icon_file_path_; 314 base::FilePath old_path = icon_file_path_;
249 icon_file_path_ = icon_file_path; 315 icon_file_path_ = icon_file_path;
250 316
251 std::string icon_name = 317 std::string icon_name =
252 icon_file_path_.BaseName().RemoveExtension().value(); 318 icon_file_path_.BaseName().RemoveExtension().value();
253 std::string icon_dir = icon_file_path_.DirName().value(); 319 std::string icon_dir = GetIconThemePath(using_kde4_, icon_file_path);
254 if (!icon_) { 320 if (!icon_) {
255 icon_ = 321 icon_ =
256 app_indicator_new_with_path(id_.c_str(), 322 app_indicator_new_with_path(id_.c_str(),
257 icon_name.c_str(), 323 icon_name.c_str(),
258 APP_INDICATOR_CATEGORY_APPLICATION_STATUS, 324 APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
259 icon_dir.c_str()); 325 icon_dir.c_str());
260 app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE); 326 app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE);
261 SetMenu(); 327 SetMenu();
262 } else { 328 } else {
263 // Currently we are creating a new temp directory every time the icon is 329 // Currently we are creating a new temp directory every time the icon is
264 // set. So we need to set the directory each time. 330 // set. So we need to set the directory each time.
265 app_indicator_set_icon_theme_path(icon_, icon_dir.c_str()); 331 app_indicator_set_icon_theme_path(icon_, icon_dir.c_str());
266 app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon"); 332 app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon");
267 333
268 // Delete previous icon directory. 334 if (ShouldCreateTempDirectoryPerImage(using_kde4_)) {
269 content::BrowserThread::GetBlockingPool()->PostTask( 335 // Delete previous icon directory.
270 FROM_HERE, 336 content::BrowserThread::GetBlockingPool()->PostTask(
271 base::Bind(&DeleteTempImagePath, old_path.DirName())); 337 FROM_HERE,
338 base::Bind(&DeleteTempDirectory, old_path.DirName()));
339 }
272 } 340 }
273 } 341 }
274 342
275 void AppIndicatorIcon::SetMenu() { 343 void AppIndicatorIcon::SetMenu() {
276 menu_.reset(new AppIndicatorIconMenu(menu_model_)); 344 menu_.reset(new AppIndicatorIconMenu(menu_model_));
277 UpdateClickActionReplacementMenuItem(); 345 UpdateClickActionReplacementMenuItem();
278 app_indicator_set_menu(icon_, menu_->GetGtkMenu()); 346 app_indicator_set_menu(icon_, menu_->GetGtkMenu());
279 } 347 }
280 348
281 void AppIndicatorIcon::UpdateClickActionReplacementMenuItem() { 349 void AppIndicatorIcon::UpdateClickActionReplacementMenuItem() {
(...skipping 10 matching lines...) Expand all
292 base::Bind(&AppIndicatorIcon::OnClickActionReplacementMenuItemActivated, 360 base::Bind(&AppIndicatorIcon::OnClickActionReplacementMenuItemActivated,
293 base::Unretained(this))); 361 base::Unretained(this)));
294 } 362 }
295 363
296 void AppIndicatorIcon::OnClickActionReplacementMenuItemActivated() { 364 void AppIndicatorIcon::OnClickActionReplacementMenuItemActivated() {
297 if (delegate()) 365 if (delegate())
298 delegate()->OnClick(); 366 delegate()->OnClick();
299 } 367 }
300 368
301 } // namespace libgtk2ui 369 } // namespace libgtk2ui
OLDNEW
« no previous file with comments | « chrome/browser/ui/libgtk2ui/app_indicator_icon.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698