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

Side by Side Diff: chrome/browser/shell_integration_linux.cc

Issue 249023: Use favicon for application shortcut icon. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fixed unittests, handle null favicon Created 11 years, 2 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/shell_integration.h ('k') | chrome/browser/shell_integration_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2009 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/shell_integration.h" 5 #include "chrome/browser/shell_integration.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 #include <sys/types.h> 10 #include <sys/types.h>
11 #include <unistd.h> 11 #include <unistd.h>
12 12
13 #include <string> 13 #include <string>
14 #include <vector> 14 #include <vector>
15 15
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/eintr_wrapper.h" 17 #include "base/eintr_wrapper.h"
18 #include "base/file_path.h" 18 #include "base/file_path.h"
19 #include "base/file_util.h" 19 #include "base/file_util.h"
20 #include "base/gfx/png_encoder.h"
20 #include "base/message_loop.h" 21 #include "base/message_loop.h"
21 #include "base/path_service.h" 22 #include "base/path_service.h"
22 #include "base/process_util.h" 23 #include "base/process_util.h"
23 #include "base/scoped_temp_dir.h" 24 #include "base/scoped_temp_dir.h"
24 #include "base/string_tokenizer.h" 25 #include "base/string_tokenizer.h"
25 #include "base/string_util.h" 26 #include "base/string_util.h"
26 #include "base/task.h" 27 #include "base/task.h"
27 #include "base/thread.h" 28 #include "base/thread.h"
28 #include "chrome/browser/browser_process.h" 29 #include "chrome/browser/browser_process.h"
29 #include "chrome/common/chrome_constants.h" 30 #include "chrome/common/chrome_constants.h"
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 115
115 virtual void Run() { 116 virtual void Run() {
116 // TODO(phajdan.jr): Report errors from this function, possibly as infobars. 117 // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
117 std::string template_contents; 118 std::string template_contents;
118 if (!GetDesktopShortcutTemplate(&template_contents)) 119 if (!GetDesktopShortcutTemplate(&template_contents))
119 return; 120 return;
120 121
121 FilePath shortcut_filename = 122 FilePath shortcut_filename =
122 ShellIntegration::GetDesktopShortcutFilename(shortcut_info_.url); 123 ShellIntegration::GetDesktopShortcutFilename(shortcut_info_.url);
123 124
125 std::string icon_name = CreateIcon(shortcut_filename);
126
124 std::string contents = ShellIntegration::GetDesktopFileContents( 127 std::string contents = ShellIntegration::GetDesktopFileContents(
125 template_contents, shortcut_info_.url, shortcut_info_.title); 128 template_contents, shortcut_info_.url, shortcut_info_.title,
129 icon_name);
126 130
127 if (shortcut_info_.create_on_desktop) 131 if (shortcut_info_.create_on_desktop)
128 CreateOnDesktop(shortcut_filename, contents); 132 CreateOnDesktop(shortcut_filename, contents);
129 133
130 if (shortcut_info_.create_in_applications_menu) 134 if (shortcut_info_.create_in_applications_menu)
131 CreateInApplicationsMenu(shortcut_filename, contents); 135 CreateInApplicationsMenu(shortcut_filename, contents);
132 } 136 }
133 137
134 private: 138 private:
139 std::string CreateIcon(const FilePath& shortcut_filename) {
140 if (shortcut_info_.favicon.isNull())
141 return std::string();
142
143 // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
144 ScopedTempDir temp_dir;
145 if (!temp_dir.CreateUniqueTempDir())
146 return std::string();
147
148 FilePath temp_file_path = temp_dir.path().Append(
149 shortcut_filename.ReplaceExtension("png"));
150
151 std::vector<unsigned char> png_data;
152 PNGEncoder::EncodeBGRASkBitmap(shortcut_info_.favicon, false, &png_data);
153 int bytes_written = file_util::WriteFile(temp_file_path,
154 reinterpret_cast<char*>(png_data.data()), png_data.size());
155
156 if (bytes_written != static_cast<int>(png_data.size()))
157 return std::string();
158
159 std::vector<std::string> argv;
160 argv.push_back("xdg-icon-resource");
161 argv.push_back("install");
162
163 // Always install in user mode, even if someone runs the browser as root
164 // (people do that).
165 argv.push_back("--mode");
166 argv.push_back("user");
167
168 argv.push_back("--size");
169 argv.push_back(IntToString(shortcut_info_.favicon.width()));
170
171 argv.push_back(temp_file_path.value());
172 std::string icon_name = temp_file_path.BaseName().RemoveExtension().value();
173 argv.push_back(icon_name);
174 LaunchXdgUtility(argv);
175 return icon_name;
176 }
177
135 void CreateOnDesktop(const FilePath& shortcut_filename, 178 void CreateOnDesktop(const FilePath& shortcut_filename,
136 const std::string& contents) { 179 const std::string& contents) {
137 // TODO(phajdan.jr): Report errors from this function, possibly as infobars. 180 // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
138 181
139 // Make sure that we will later call openat in a secure way. 182 // Make sure that we will later call openat in a secure way.
140 DCHECK_EQ(shortcut_filename.BaseName().value(), shortcut_filename.value()); 183 DCHECK_EQ(shortcut_filename.BaseName().value(), shortcut_filename.value());
141 184
142 FilePath desktop_path; 185 FilePath desktop_path;
143 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) 186 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
144 return; 187 return;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 ScopedTempDir temp_dir; 219 ScopedTempDir temp_dir;
177 if (!temp_dir.CreateUniqueTempDir()) 220 if (!temp_dir.CreateUniqueTempDir())
178 return; 221 return;
179 222
180 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); 223 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename);
181 224
182 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), 225 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(),
183 contents.length()); 226 contents.length());
184 227
185 if (bytes_written != static_cast<int>(contents.length())) 228 if (bytes_written != static_cast<int>(contents.length()))
186 return; 229 return;
187 230
188 std::vector<std::string> argv; 231 std::vector<std::string> argv;
189 argv.push_back("xdg-desktop-menu"); 232 argv.push_back("xdg-desktop-menu");
190 argv.push_back("install"); 233 argv.push_back("install");
191 234
192 // Always install in user mode, even if someone runs the browser as root 235 // Always install in user mode, even if someone runs the browser as root
193 // (people do that). 236 // (people do that).
194 argv.push_back("--mode"); 237 argv.push_back("--mode");
195 argv.push_back("user"); 238 argv.push_back("user");
196 239
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 L"-" + UTF8ToWide(url.spec()) + L".desktop"; 297 L"-" + UTF8ToWide(url.spec()) + L".desktop";
255 file_util::ReplaceIllegalCharacters(&filename, '_'); 298 file_util::ReplaceIllegalCharacters(&filename, '_');
256 299
257 // Return BaseName to be absolutely sure we're not vulnerable to a directory 300 // Return BaseName to be absolutely sure we're not vulnerable to a directory
258 // traversal attack. 301 // traversal attack.
259 return FilePath::FromWStringHack(filename).BaseName(); 302 return FilePath::FromWStringHack(filename).BaseName();
260 } 303 }
261 304
262 std::string ShellIntegration::GetDesktopFileContents( 305 std::string ShellIntegration::GetDesktopFileContents(
263 const std::string& template_contents, const GURL& url, 306 const std::string& template_contents, const GURL& url,
264 const string16& title) { 307 const string16& title, const std::string& icon_name) {
265 // See http://standards.freedesktop.org/desktop-entry-spec/latest/ 308 // See http://standards.freedesktop.org/desktop-entry-spec/latest/
266 // Although not required by the spec, Nautilus on Ubuntu Karmic creates its 309 // Although not required by the spec, Nautilus on Ubuntu Karmic creates its
267 // launchers with an xdg-open shebang. Follow that convention. 310 // launchers with an xdg-open shebang. Follow that convention.
268 std::string output_buffer("#!/usr/bin/env xdg-open\n"); 311 std::string output_buffer("#!/usr/bin/env xdg-open\n");
269 StringTokenizer tokenizer(template_contents, "\n"); 312 StringTokenizer tokenizer(template_contents, "\n");
270 while (tokenizer.GetNext()) { 313 while (tokenizer.GetNext()) {
271 // TODO(phajdan.jr): Add the icon.
272
273 if (tokenizer.token().substr(0, 5) == "Exec=") { 314 if (tokenizer.token().substr(0, 5) == "Exec=") {
274 std::string exec_path = tokenizer.token().substr(5); 315 std::string exec_path = tokenizer.token().substr(5);
275 StringTokenizer exec_tokenizer(exec_path, " "); 316 StringTokenizer exec_tokenizer(exec_path, " ");
276 std::string final_path; 317 std::string final_path;
277 while (exec_tokenizer.GetNext()) { 318 while (exec_tokenizer.GetNext()) {
278 if (exec_tokenizer.token() != "%U") 319 if (exec_tokenizer.token() != "%U")
279 final_path += exec_tokenizer.token() + " "; 320 final_path += exec_tokenizer.token() + " ";
280 } 321 }
281 std::wstring app_switch_wide(switches::kApp); 322 std::wstring app_switch_wide(switches::kApp);
282 std::string app_switch(StringPrintf("\"--%s=%s\"", 323 std::string app_switch(StringPrintf("\"--%s=%s\"",
283 WideToUTF8(app_switch_wide).c_str(), 324 WideToUTF8(app_switch_wide).c_str(),
284 url.spec().c_str())); 325 url.spec().c_str()));
285 // Sanitize the command line string. 326 // Sanitize the command line string.
286 ReplaceSubstringsAfterOffset(&app_switch, 0, "%", "%%"); 327 ReplaceSubstringsAfterOffset(&app_switch, 0, "%", "%%");
287 ReplaceSubstringsAfterOffset(&app_switch, 0, ";", ""); 328 ReplaceSubstringsAfterOffset(&app_switch, 0, ";", "");
288 ReplaceSubstringsAfterOffset(&app_switch, 0, "$", ""); 329 ReplaceSubstringsAfterOffset(&app_switch, 0, "$", "");
289 output_buffer += std::string("Exec=") + final_path + app_switch + "\n"; 330 output_buffer += std::string("Exec=") + final_path + app_switch + "\n";
290 } else if (tokenizer.token().substr(0, 5) == "Name=") { 331 } else if (tokenizer.token().substr(0, 5) == "Name=") {
291 std::string final_title = UTF16ToUTF8(title); 332 std::string final_title = UTF16ToUTF8(title);
292 // Make sure no endline characters can slip in and possibly introduce 333 // Make sure no endline characters can slip in and possibly introduce
293 // additional lines (like Exec, which makes it a security risk). Also 334 // additional lines (like Exec, which makes it a security risk). Also
294 // use the URL as a default when the title is empty. 335 // use the URL as a default when the title is empty.
295 if (final_title.empty() || 336 if (final_title.empty() ||
296 final_title.find("\n") != std::string::npos || 337 final_title.find("\n") != std::string::npos ||
297 final_title.find("\r") != std::string::npos) 338 final_title.find("\r") != std::string::npos) {
298 final_title = url.spec(); 339 final_title = url.spec();
340 }
299 output_buffer += StringPrintf("Name=%s\n", final_title.c_str()); 341 output_buffer += StringPrintf("Name=%s\n", final_title.c_str());
300 } else if (tokenizer.token().substr(0, 11) == "GenericName" || 342 } else if (tokenizer.token().substr(0, 11) == "GenericName" ||
301 tokenizer.token().substr(0, 7) == "Comment" || 343 tokenizer.token().substr(0, 7) == "Comment" ||
302 tokenizer.token().substr(0, 1) == "#") { 344 tokenizer.token().substr(0, 1) == "#") {
303 // Skip comment lines. 345 // Skip comment lines.
346 } else if (tokenizer.token().substr(0, 5) == "Icon=" &&
347 !icon_name.empty()) {
348 output_buffer += StringPrintf("Icon=%s\n", icon_name.c_str());
304 } else { 349 } else {
305 output_buffer += tokenizer.token() + "\n"; 350 output_buffer += tokenizer.token() + "\n";
306 } 351 }
307 } 352 }
308 return output_buffer; 353 return output_buffer;
309 } 354 }
310 355
311 void ShellIntegration::CreateDesktopShortcut( 356 void ShellIntegration::CreateDesktopShortcut(
312 const ShortcutInfo& shortcut_info) { 357 const ShortcutInfo& shortcut_info) {
313 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, 358 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
314 new CreateDesktopShortcutTask(shortcut_info)); 359 new CreateDesktopShortcutTask(shortcut_info));
315 } 360 }
OLDNEW
« no previous file with comments | « chrome/browser/shell_integration.h ('k') | chrome/browser/shell_integration_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698