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 "chrome/browser/web_applications/web_app.h" | 5 #include "chrome/browser/web_applications/web_app.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <shlobj.h> | 8 #include <shlobj.h> |
9 #endif // defined(OS_WIN) | 9 #endif // defined(OS_WIN) |
10 | 10 |
11 #include "base/bind.h" | |
11 #include "base/command_line.h" | 12 #include "base/command_line.h" |
12 #include "base/file_util.h" | 13 #include "base/file_util.h" |
13 #include "base/i18n/file_util_icu.h" | 14 #include "base/i18n/file_util_icu.h" |
14 #include "base/md5.h" | 15 #include "base/md5.h" |
15 #include "base/path_service.h" | 16 #include "base/path_service.h" |
16 #include "base/string_util.h" | 17 #include "base/string_util.h" |
17 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
18 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
19 #include "base/win/windows_version.h" | 20 #include "base/win/windows_version.h" |
20 #include "chrome/common/chrome_constants.h" | 21 #include "chrome/common/chrome_constants.h" |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
141 base::MD5Digest downloaded_image_checksum; | 142 base::MD5Digest downloaded_image_checksum; |
142 GetImageCheckSum(image, &downloaded_image_checksum); | 143 GetImageCheckSum(image, &downloaded_image_checksum); |
143 | 144 |
144 // Update icon if checksums are not equal. | 145 // Update icon if checksums are not equal. |
145 return memcmp(&persisted_image_checksum, &downloaded_image_checksum, | 146 return memcmp(&persisted_image_checksum, &downloaded_image_checksum, |
146 sizeof(base::MD5Digest)) != 0; | 147 sizeof(base::MD5Digest)) != 0; |
147 } | 148 } |
148 | 149 |
149 #endif // defined(OS_WIN) | 150 #endif // defined(OS_WIN) |
150 | 151 |
151 // Represents a task that creates web application shortcut. This runs on | 152 void CreateShortcutTask(const FilePath& web_app_path, |
152 // file thread and schedules the callback (if any) on the calling thread | 153 const FilePath& profile_path, |
153 // when finished (either success or failure). | 154 const ShellIntegration::ShortcutInfo& shortcut_info) { |
154 class CreateShortcutTask : public Task { | |
155 public: | |
156 CreateShortcutTask(const FilePath& profile_path, | |
157 const ShellIntegration::ShortcutInfo& shortcut_info, | |
158 web_app::CreateShortcutCallback* callback); | |
159 | |
160 private: | |
161 class CreateShortcutCallbackTask : public Task { | |
162 public: | |
163 CreateShortcutCallbackTask(web_app::CreateShortcutCallback* callback, | |
164 bool success) | |
165 : callback_(callback), | |
166 success_(success) { | |
167 } | |
168 | |
169 // Overridden from Task: | |
170 virtual void Run() { | |
171 callback_->Run(success_); | |
172 } | |
173 | |
174 private: | |
175 web_app::CreateShortcutCallback* callback_; | |
176 bool success_; | |
177 }; | |
178 | |
179 // Overridden from Task: | |
180 virtual void Run(); | |
181 | |
182 // Returns true if shortcut is created successfully. | |
183 bool CreateShortcut(); | |
184 | |
185 // Path to store persisted data for web app. | |
186 FilePath web_app_path_; | |
187 | |
188 // Out copy of profile path. | |
189 FilePath profile_path_; | |
190 | |
191 // Our copy of short cut data. | |
192 ShellIntegration::ShortcutInfo shortcut_info_; | |
193 | |
194 // Callback when task is finished. | |
195 web_app::CreateShortcutCallback* callback_; | |
196 MessageLoop* message_loop_; | |
197 | |
198 DISALLOW_COPY_AND_ASSIGN(CreateShortcutTask); | |
199 }; | |
200 | |
201 CreateShortcutTask::CreateShortcutTask( | |
202 const FilePath& profile_path, | |
203 const ShellIntegration::ShortcutInfo& shortcut_info, | |
204 web_app::CreateShortcutCallback* callback) | |
205 : web_app_path_(web_app::internals::GetWebAppDataDirectory( | |
206 web_app::GetDataDir(profile_path), | |
207 shortcut_info)), | |
208 profile_path_(profile_path), | |
209 shortcut_info_(shortcut_info), | |
210 callback_(callback), | |
211 message_loop_(MessageLoop::current()) { | |
212 DCHECK(message_loop_ != NULL); | |
213 } | |
214 | |
215 void CreateShortcutTask::Run() { | |
216 bool success = CreateShortcut(); | |
217 | |
218 if (callback_ != NULL) | |
219 message_loop_->PostTask(FROM_HERE, | |
220 new CreateShortcutCallbackTask(callback_, success)); | |
221 } | |
222 | |
223 bool CreateShortcutTask::CreateShortcut() { | |
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
225 | 156 |
226 #if defined(OS_POSIX) && !defined(OS_MACOSX) | 157 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
227 scoped_ptr<base::Environment> env(base::Environment::Create()); | 158 scoped_ptr<base::Environment> env(base::Environment::Create()); |
228 | 159 |
229 std::string shortcut_template; | 160 std::string shortcut_template; |
230 if (!ShellIntegration::GetDesktopShortcutTemplate(env.get(), | 161 if (!ShellIntegration::GetDesktopShortcutTemplate(env.get(), |
231 &shortcut_template)) { | 162 &shortcut_template)) { |
232 return false; | 163 return; |
233 } | 164 } |
234 ShellIntegration::CreateDesktopShortcut(shortcut_info_, shortcut_template); | 165 ShellIntegration::CreateDesktopShortcut(shortcut_info, shortcut_template); |
235 return true; // assuming always success. | 166 return; // assuming always success. |
236 #elif defined(OS_WIN) | 167 #elif defined(OS_WIN) |
237 // Shortcut paths under which to create shortcuts. | 168 // Shortcut paths under which to create shortcuts. |
238 std::vector<FilePath> shortcut_paths; | 169 std::vector<FilePath> shortcut_paths; |
239 | 170 |
240 // Locations to add to shortcut_paths. | 171 // Locations to add to shortcut_paths. |
241 struct { | 172 struct { |
242 const bool& use_this_location; | 173 const bool& use_this_location; |
243 int location_id; | 174 int location_id; |
244 const wchar_t* sub_dir; | 175 const wchar_t* sub_dir; |
245 } locations[] = { | 176 } locations[] = { |
246 { | 177 { |
247 shortcut_info_.create_on_desktop, | 178 shortcut_info.create_on_desktop, |
248 chrome::DIR_USER_DESKTOP, | 179 chrome::DIR_USER_DESKTOP, |
249 NULL | 180 NULL |
250 }, { | 181 }, { |
251 shortcut_info_.create_in_applications_menu, | 182 shortcut_info.create_in_applications_menu, |
252 base::DIR_START_MENU, | 183 base::DIR_START_MENU, |
253 NULL | 184 NULL |
254 }, { | 185 }, { |
255 shortcut_info_.create_in_quick_launch_bar, | 186 shortcut_info.create_in_quick_launch_bar, |
256 // For Win7, create_in_quick_launch_bar means pinning to taskbar. Use | 187 // For Win7, create_in_quick_launch_bar means pinning to taskbar. Use |
257 // base::PATH_START as a flag for this case. | 188 // base::PATH_START as a flag for this case. |
258 (base::win::GetVersion() >= base::win::VERSION_WIN7) ? | 189 (base::win::GetVersion() >= base::win::VERSION_WIN7) ? |
259 base::PATH_START : base::DIR_APP_DATA, | 190 base::PATH_START : base::DIR_APP_DATA, |
260 (base::win::GetVersion() >= base::win::VERSION_WIN7) ? | 191 (base::win::GetVersion() >= base::win::VERSION_WIN7) ? |
261 NULL : L"Microsoft\\Internet Explorer\\Quick Launch" | 192 NULL : L"Microsoft\\Internet Explorer\\Quick Launch" |
262 } | 193 } |
263 }; | 194 }; |
264 | 195 |
265 // Populate shortcut_paths. | 196 // Populate shortcut_paths. |
266 for (int i = 0; i < arraysize(locations); ++i) { | 197 for (int i = 0; i < arraysize(locations); ++i) { |
267 if (locations[i].use_this_location) { | 198 if (locations[i].use_this_location) { |
268 FilePath path; | 199 FilePath path; |
269 | 200 |
270 // Skip the Win7 case. | 201 // Skip the Win7 case. |
271 if (locations[i].location_id == base::PATH_START) | 202 if (locations[i].location_id == base::PATH_START) |
272 continue; | 203 continue; |
273 | 204 |
274 if (!PathService::Get(locations[i].location_id, &path)) { | 205 if (!PathService::Get(locations[i].location_id, &path)) { |
275 NOTREACHED(); | 206 NOTREACHED(); |
276 return false; | 207 return; |
277 } | 208 } |
278 | 209 |
279 if (locations[i].sub_dir != NULL) | 210 if (locations[i].sub_dir != NULL) |
280 path = path.Append(locations[i].sub_dir); | 211 path = path.Append(locations[i].sub_dir); |
281 | 212 |
282 shortcut_paths.push_back(path); | 213 shortcut_paths.push_back(path); |
283 } | 214 } |
284 } | 215 } |
285 | 216 |
286 bool pin_to_taskbar = | 217 bool pin_to_taskbar = |
287 shortcut_info_.create_in_quick_launch_bar && | 218 shortcut_info.create_in_quick_launch_bar && |
288 (base::win::GetVersion() >= base::win::VERSION_WIN7); | 219 (base::win::GetVersion() >= base::win::VERSION_WIN7); |
289 | 220 |
290 // For Win7's pinning support, any shortcut could be used. So we only create | 221 // For Win7's pinning support, any shortcut could be used. So we only create |
291 // the shortcut file when there is no shortcut file will be created. That is, | 222 // the shortcut file when there is no shortcut file will be created. That is, |
292 // user only selects "Pin to taskbar". | 223 // user only selects "Pin to taskbar". |
293 if (pin_to_taskbar && shortcut_paths.empty()) { | 224 if (pin_to_taskbar && shortcut_paths.empty()) { |
294 // Creates the shortcut in web_app_path_ in this case. | 225 // Creates the shortcut in web_app_path in this case. |
295 shortcut_paths.push_back(web_app_path_); | 226 shortcut_paths.push_back(web_app_path); |
296 } | 227 } |
297 | 228 |
298 if (shortcut_paths.empty()) { | 229 if (shortcut_paths.empty()) { |
299 NOTREACHED(); | 230 NOTREACHED(); |
James Hawkins
2011/12/08 18:43:56
Either remove these NOTREACHEDs or remove the retu
dcheng
2011/12/08 18:51:28
Done.
| |
300 return false; | 231 return; |
301 } | 232 } |
302 | 233 |
303 // Ensure web_app_path_ exists. | 234 // Ensure web_app_path exists. |
304 if (!file_util::PathExists(web_app_path_) && | 235 if (!file_util::PathExists(web_app_path) && |
305 !file_util::CreateDirectory(web_app_path_)) { | 236 !file_util::CreateDirectory(web_app_path)) { |
306 NOTREACHED(); | 237 NOTREACHED(); |
307 return false; | 238 return; |
308 } | 239 } |
309 | 240 |
310 // Generates file name to use with persisted ico and shortcut file. | 241 // Generates file name to use with persisted ico and shortcut file. |
311 FilePath file_name = | 242 FilePath file_name = |
312 web_app::internals::GetSanitizedFileName(shortcut_info_.title); | 243 web_app::internals::GetSanitizedFileName(shortcut_info.title); |
313 | 244 |
314 // Creates an ico file to use with shortcut. | 245 // Creates an ico file to use with shortcut. |
315 FilePath icon_file = web_app_path_.Append(file_name).ReplaceExtension( | 246 FilePath icon_file = web_app_path.Append(file_name).ReplaceExtension( |
316 FILE_PATH_LITERAL(".ico")); | 247 FILE_PATH_LITERAL(".ico")); |
317 if (!web_app::internals::CheckAndSaveIcon(icon_file, | 248 if (!web_app::internals::CheckAndSaveIcon(icon_file, |
318 shortcut_info_.favicon)) { | 249 shortcut_info.favicon)) { |
319 NOTREACHED(); | 250 NOTREACHED(); |
320 return false; | 251 return; |
321 } | 252 } |
322 | 253 |
323 FilePath chrome_exe; | 254 FilePath chrome_exe; |
324 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 255 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
325 NOTREACHED(); | 256 NOTREACHED(); |
326 return false; | 257 return; |
327 } | 258 } |
328 | 259 |
329 // Working directory. | 260 // Working directory. |
330 FilePath chrome_folder = chrome_exe.DirName(); | 261 FilePath chrome_folder = chrome_exe.DirName(); |
331 | 262 |
332 CommandLine cmd_line = | 263 CommandLine cmd_line = |
333 ShellIntegration::CommandLineArgsForLauncher(shortcut_info_.url, | 264 ShellIntegration::CommandLineArgsForLauncher(shortcut_info.url, |
334 shortcut_info_.extension_id); | 265 shortcut_info.extension_id); |
335 // TODO(evan): we rely on the fact that command_line_string() is | 266 // TODO(evan): we rely on the fact that command_line_string() is |
336 // properly quoted for a Windows command line. The method on | 267 // properly quoted for a Windows command line. The method on |
337 // CommandLine should probably be renamed to better reflect that | 268 // CommandLine should probably be renamed to better reflect that |
338 // fact. | 269 // fact. |
339 std::wstring wide_switches(cmd_line.GetCommandLineString()); | 270 string16 wide_switches(cmd_line.GetCommandLineString()); |
340 | 271 |
341 // Sanitize description | 272 // Sanitize description |
342 if (shortcut_info_.description.length() >= MAX_PATH) | 273 string16 description = shortcut_info.description; |
343 shortcut_info_.description.resize(MAX_PATH - 1); | 274 if (description.length() >= MAX_PATH) |
275 description.resize(MAX_PATH - 1); | |
344 | 276 |
345 // Generates app id from web app url and profile path. | 277 // Generates app id from web app url and profile path. |
346 std::string app_name = | 278 std::string app_name = |
347 web_app::GenerateApplicationNameFromInfo(shortcut_info_); | 279 web_app::GenerateApplicationNameFromInfo(shortcut_info); |
348 std::wstring app_id = ShellIntegration::GetAppId( | 280 std::wstring app_id = ShellIntegration::GetAppId( |
349 UTF8ToWide(app_name), profile_path_); | 281 UTF8ToWide(app_name), profile_path); |
350 | 282 |
351 FilePath shortcut_to_pin; | 283 FilePath shortcut_to_pin; |
352 | 284 |
353 bool success = true; | 285 bool success = true; |
354 for (size_t i = 0; i < shortcut_paths.size(); ++i) { | 286 for (size_t i = 0; i < shortcut_paths.size(); ++i) { |
355 FilePath shortcut_file = shortcut_paths[i].Append(file_name). | 287 FilePath shortcut_file = shortcut_paths[i].Append(file_name). |
356 ReplaceExtension(FILE_PATH_LITERAL(".lnk")); | 288 ReplaceExtension(FILE_PATH_LITERAL(".lnk")); |
357 | 289 |
358 int unique_number = DownloadFile::GetUniquePathNumber(shortcut_file); | 290 int unique_number = DownloadFile::GetUniquePathNumber(shortcut_file); |
359 if (unique_number == -1) { | 291 if (unique_number == -1) { |
360 success = false; | 292 success = false; |
361 continue; | 293 continue; |
362 } else if (unique_number > 0) { | 294 } else if (unique_number > 0) { |
363 DownloadFile::AppendNumberToPath(&shortcut_file, unique_number); | 295 DownloadFile::AppendNumberToPath(&shortcut_file, unique_number); |
364 } | 296 } |
365 | 297 |
366 success &= file_util::CreateShortcutLink(chrome_exe.value().c_str(), | 298 success &= file_util::CreateShortcutLink(chrome_exe.value().c_str(), |
367 shortcut_file.value().c_str(), | 299 shortcut_file.value().c_str(), |
368 chrome_folder.value().c_str(), | 300 chrome_folder.value().c_str(), |
369 wide_switches.c_str(), | 301 wide_switches.c_str(), |
370 shortcut_info_.description.c_str(), | 302 description.c_str(), |
371 icon_file.value().c_str(), | 303 icon_file.value().c_str(), |
372 0, | 304 0, |
373 app_id.c_str()); | 305 app_id.c_str()); |
374 | 306 |
375 // Any shortcut would work for the pinning. We use the first one. | 307 // Any shortcut would work for the pinning. We use the first one. |
376 if (success && pin_to_taskbar && shortcut_to_pin.empty()) | 308 if (success && pin_to_taskbar && shortcut_to_pin.empty()) |
377 shortcut_to_pin = shortcut_file; | 309 shortcut_to_pin = shortcut_file; |
378 } | 310 } |
379 | 311 |
380 if (success && pin_to_taskbar) { | 312 if (success && pin_to_taskbar) { |
381 if (!shortcut_to_pin.empty()) { | 313 if (!shortcut_to_pin.empty()) { |
382 success &= file_util::TaskbarPinShortcutLink( | 314 success &= file_util::TaskbarPinShortcutLink( |
383 shortcut_to_pin.value().c_str()); | 315 shortcut_to_pin.value().c_str()); |
384 } else { | 316 } else { |
385 NOTREACHED(); | 317 NOTREACHED(); |
386 success = false; | 318 success = false; |
387 } | 319 } |
388 } | 320 } |
389 | 321 |
390 return success; | 322 return; |
James Hawkins
2011/12/08 18:43:56
No need to return
dcheng
2011/12/08 18:51:28
Done.
| |
391 #else | 323 #else |
392 NOTIMPLEMENTED(); | 324 NOTIMPLEMENTED(); |
393 return false; | 325 return; |
James Hawkins
2011/12/08 18:43:56
No need to return
dcheng
2011/12/08 18:51:28
Done.
| |
394 #endif | 326 #endif |
395 } | 327 } |
396 | 328 |
397 } // namespace | 329 } // namespace |
398 | 330 |
399 namespace web_app { | 331 namespace web_app { |
400 | 332 |
401 // The following string is used to build the directory name for | 333 // The following string is used to build the directory name for |
402 // shortcuts to chrome applications (the kind which are installed | 334 // shortcuts to chrome applications (the kind which are installed |
403 // from a CRX). Application shortcuts to URLs use the {host}_{path} | 335 // from a CRX). Application shortcuts to URLs use the {host}_{path} |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
479 | 411 |
480 std::string GetExtensionIdFromApplicationName(const std::string& app_name) { | 412 std::string GetExtensionIdFromApplicationName(const std::string& app_name) { |
481 std::string prefix(kCrxAppPrefix); | 413 std::string prefix(kCrxAppPrefix); |
482 if (app_name.substr(0, prefix.length()) != prefix) | 414 if (app_name.substr(0, prefix.length()) != prefix) |
483 return std::string(); | 415 return std::string(); |
484 return app_name.substr(prefix.length()); | 416 return app_name.substr(prefix.length()); |
485 } | 417 } |
486 | 418 |
487 void CreateShortcut( | 419 void CreateShortcut( |
488 const FilePath& data_dir, | 420 const FilePath& data_dir, |
489 const ShellIntegration::ShortcutInfo& shortcut_info, | 421 const ShellIntegration::ShortcutInfo& shortcut_info) { |
490 CreateShortcutCallback* callback) { | 422 BrowserThread::PostTask( |
491 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 423 BrowserThread::FILE, |
492 new CreateShortcutTask(data_dir, shortcut_info, callback)); | 424 FROM_HERE, |
425 base::Bind(&CreateShortcutTask, | |
426 web_app::internals::GetWebAppDataDirectory( | |
427 web_app::GetDataDir(data_dir), | |
428 shortcut_info), | |
429 data_dir, | |
430 shortcut_info)); | |
493 } | 431 } |
494 | 432 |
495 bool IsValidUrl(const GURL& url) { | 433 bool IsValidUrl(const GURL& url) { |
496 static const char* const kValidUrlSchemes[] = { | 434 static const char* const kValidUrlSchemes[] = { |
497 chrome::kFileScheme, | 435 chrome::kFileScheme, |
498 chrome::kFtpScheme, | 436 chrome::kFtpScheme, |
499 chrome::kHttpScheme, | 437 chrome::kHttpScheme, |
500 chrome::kHttpsScheme, | 438 chrome::kHttpsScheme, |
501 chrome::kExtensionScheme, | 439 chrome::kExtensionScheme, |
502 }; | 440 }; |
(...skipping 29 matching lines...) Expand all Loading... | |
532 | 470 |
533 #if defined(TOOLKIT_USES_GTK) | 471 #if defined(TOOLKIT_USES_GTK) |
534 std::string GetWMClassFromAppName(std::string app_name) { | 472 std::string GetWMClassFromAppName(std::string app_name) { |
535 file_util::ReplaceIllegalCharactersInPath(&app_name, '_'); | 473 file_util::ReplaceIllegalCharactersInPath(&app_name, '_'); |
536 TrimString(app_name, "_", &app_name); | 474 TrimString(app_name, "_", &app_name); |
537 return app_name; | 475 return app_name; |
538 } | 476 } |
539 #endif | 477 #endif |
540 | 478 |
541 } // namespace web_app | 479 } // namespace web_app |
OLD | NEW |