OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_win.h" | 5 #include "chrome/browser/web_applications/web_app_win.h" |
6 | 6 |
7 #include <shlobj.h> | 7 #include <shlobj.h> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/md5.h" | 13 #include "base/md5.h" |
| 14 #include "base/memory/scoped_ptr.h" |
14 #include "base/path_service.h" | 15 #include "base/path_service.h" |
15 #include "base/strings/string16.h" | 16 #include "base/strings/string16.h" |
16 #include "base/strings/string_piece.h" | 17 #include "base/strings/string_piece.h" |
17 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
19 #include "base/win/shortcut.h" | 20 #include "base/win/shortcut.h" |
20 #include "base/win/windows_version.h" | 21 #include "base/win/windows_version.h" |
21 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
22 #include "chrome/browser/web_applications/update_shortcut_worker_win.h" | 23 #include "chrome/browser/web_applications/update_shortcut_worker_win.h" |
23 #include "chrome/common/chrome_switches.h" | 24 #include "chrome/common/chrome_switches.h" |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 for (std::vector<base::FilePath>::const_iterator j = shortcut_files.begin(); | 328 for (std::vector<base::FilePath>::const_iterator j = shortcut_files.begin(); |
328 j != shortcut_files.end(); ++j) { | 329 j != shortcut_files.end(); ++j) { |
329 // Any shortcut could have been pinned, either by chrome or the user, so | 330 // Any shortcut could have been pinned, either by chrome or the user, so |
330 // they are all unpinned. | 331 // they are all unpinned. |
331 base::win::TaskbarUnpinShortcutLink(j->value().c_str()); | 332 base::win::TaskbarUnpinShortcutLink(j->value().c_str()); |
332 base::DeleteFile(*j, false); | 333 base::DeleteFile(*j, false); |
333 } | 334 } |
334 } | 335 } |
335 } | 336 } |
336 | 337 |
337 void CreateIconAndSetRelaunchDetails(const base::FilePath& web_app_path, | 338 void CreateIconAndSetRelaunchDetails( |
338 const base::FilePath& icon_file, | 339 const base::FilePath& web_app_path, |
339 const web_app::ShortcutInfo& shortcut_info, | 340 const base::FilePath& icon_file, |
340 HWND hwnd) { | 341 scoped_ptr<web_app::ShortcutInfo> shortcut_info, |
| 342 HWND hwnd) { |
341 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | 343 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
342 | 344 |
343 base::CommandLine command_line = | 345 base::CommandLine command_line = ShellIntegration::CommandLineArgsForLauncher( |
344 ShellIntegration::CommandLineArgsForLauncher(shortcut_info.url, | 346 shortcut_info->url, shortcut_info->extension_id, |
345 shortcut_info.extension_id, | 347 shortcut_info->profile_path); |
346 shortcut_info.profile_path); | |
347 | 348 |
348 base::FilePath chrome_exe; | 349 base::FilePath chrome_exe; |
349 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { | 350 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { |
350 NOTREACHED(); | 351 NOTREACHED(); |
351 return; | 352 return; |
352 } | 353 } |
353 command_line.SetProgram(chrome_exe); | 354 command_line.SetProgram(chrome_exe); |
354 ui::win::SetRelaunchDetailsForWindow( | 355 ui::win::SetRelaunchDetailsForWindow(command_line.GetCommandLineString(), |
355 command_line.GetCommandLineString(), shortcut_info.title, hwnd); | 356 shortcut_info->title, hwnd); |
356 | 357 |
357 if (!base::PathExists(web_app_path) && !base::CreateDirectory(web_app_path)) | 358 if (!base::PathExists(web_app_path) && !base::CreateDirectory(web_app_path)) |
358 return; | 359 return; |
359 | 360 |
360 ui::win::SetAppIconForWindow(icon_file.value(), hwnd); | 361 ui::win::SetAppIconForWindow(icon_file.value(), hwnd); |
361 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon, true); | 362 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info->favicon, true); |
362 } | 363 } |
363 | 364 |
364 void OnShortcutInfoLoadedForSetRelaunchDetails( | 365 void OnShortcutInfoLoadedForSetRelaunchDetails( |
365 HWND hwnd, | 366 HWND hwnd, |
366 const web_app::ShortcutInfo& shortcut_info) { | 367 scoped_ptr<web_app::ShortcutInfo> shortcut_info) { |
367 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 368 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
368 | 369 |
369 // Set window's icon to the one we're about to create/update in the web app | 370 // Set window's icon to the one we're about to create/update in the web app |
370 // path. The icon cache will refresh on icon creation. | 371 // path. The icon cache will refresh on icon creation. |
371 base::FilePath web_app_path = | 372 base::FilePath web_app_path = web_app::GetWebAppDataDirectory( |
372 web_app::GetWebAppDataDirectory(shortcut_info.profile_path, | 373 shortcut_info->profile_path, shortcut_info->extension_id, |
373 shortcut_info.extension_id, | 374 shortcut_info->url); |
374 shortcut_info.url); | |
375 base::FilePath icon_file = | 375 base::FilePath icon_file = |
376 web_app::internals::GetIconFilePath(web_app_path, shortcut_info.title); | 376 web_app::internals::GetIconFilePath(web_app_path, shortcut_info->title); |
377 content::BrowserThread::PostBlockingPoolTask( | 377 content::BrowserThread::PostBlockingPoolTask( |
378 FROM_HERE, | 378 FROM_HERE, base::Bind(&CreateIconAndSetRelaunchDetails, web_app_path, |
379 base::Bind(&CreateIconAndSetRelaunchDetails, | 379 icon_file, base::Passed(&shortcut_info), hwnd)); |
380 web_app_path, | |
381 icon_file, | |
382 shortcut_info, | |
383 hwnd)); | |
384 } | 380 } |
385 | 381 |
386 // Creates an "app shim exe" by linking or copying the generic app shim exe. | 382 // Creates an "app shim exe" by linking or copying the generic app shim exe. |
387 // This is the binary that will be run when the user opens a file with this | 383 // This is the binary that will be run when the user opens a file with this |
388 // application. The name and icon of the binary will be used on the Open With | 384 // application. The name and icon of the binary will be used on the Open With |
389 // menu. For this reason, we cannot simply launch chrome.exe. We give the app | 385 // menu. For this reason, we cannot simply launch chrome.exe. We give the app |
390 // shim exe the same name as the application (with no ".exe" extension), so that | 386 // shim exe the same name as the application (with no ".exe" extension), so that |
391 // the correct title will appear on the Open With menu. (Note: we also need a | 387 // the correct title will appear on the Open With menu. (Note: we also need a |
392 // separate binary per app because Windows only allows a single association with | 388 // separate binary per app because Windows only allows a single association with |
393 // each executable.) | 389 // each executable.) |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 nullptr, nullptr); | 514 nullptr, nullptr); |
519 } | 515 } |
520 | 516 |
521 return num_successes == file_handlers_info.size(); | 517 return num_successes == file_handlers_info.size(); |
522 } | 518 } |
523 | 519 |
524 } // namespace | 520 } // namespace |
525 | 521 |
526 namespace web_app { | 522 namespace web_app { |
527 | 523 |
528 base::FilePath CreateShortcutInWebAppDir(const base::FilePath& web_app_dir, | 524 base::FilePath CreateShortcutInWebAppDir( |
529 const ShortcutInfo& shortcut_info) { | 525 const base::FilePath& web_app_dir, |
| 526 scoped_ptr<ShortcutInfo> shortcut_info) { |
530 std::vector<base::FilePath> paths; | 527 std::vector<base::FilePath> paths; |
531 paths.push_back(web_app_dir); | 528 paths.push_back(web_app_dir); |
532 std::vector<base::FilePath> out_filenames; | 529 std::vector<base::FilePath> out_filenames; |
533 base::FilePath web_app_dir_shortcut = | 530 base::FilePath web_app_dir_shortcut = |
534 web_app_dir.Append(internals::GetSanitizedFileName(shortcut_info.title)) | 531 web_app_dir.Append(internals::GetSanitizedFileName(shortcut_info->title)) |
535 .AddExtension(installer::kLnkExt); | 532 .AddExtension(installer::kLnkExt); |
536 if (!PathExists(web_app_dir_shortcut)) { | 533 if (!PathExists(web_app_dir_shortcut)) { |
537 CreateShortcutsInPaths(web_app_dir, | 534 CreateShortcutsInPaths(web_app_dir, *shortcut_info, paths, |
538 shortcut_info, | 535 SHORTCUT_CREATION_BY_USER, &out_filenames); |
539 paths, | |
540 SHORTCUT_CREATION_BY_USER, | |
541 &out_filenames); | |
542 DCHECK_EQ(out_filenames.size(), 1u); | 536 DCHECK_EQ(out_filenames.size(), 1u); |
543 DCHECK_EQ(out_filenames[0].value(), web_app_dir_shortcut.value()); | 537 DCHECK_EQ(out_filenames[0].value(), web_app_dir_shortcut.value()); |
544 } else { | 538 } else { |
545 internals::CheckAndSaveIcon( | 539 internals::CheckAndSaveIcon( |
546 internals::GetIconFilePath(web_app_dir, shortcut_info.title), | 540 internals::GetIconFilePath(web_app_dir, shortcut_info->title), |
547 shortcut_info.favicon, true); | 541 shortcut_info->favicon, true); |
548 } | 542 } |
549 return web_app_dir_shortcut; | 543 return web_app_dir_shortcut; |
550 } | 544 } |
551 | 545 |
552 void UpdateRelaunchDetailsForApp(Profile* profile, | 546 void UpdateRelaunchDetailsForApp(Profile* profile, |
553 const extensions::Extension* extension, | 547 const extensions::Extension* extension, |
554 HWND hwnd) { | 548 HWND hwnd) { |
555 web_app::GetShortcutInfoForApp( | 549 web_app::GetShortcutInfoForApp( |
556 extension, | 550 extension, |
557 profile, | 551 profile, |
(...skipping 21 matching lines...) Expand all Loading... |
579 // see explorer rebuilding the icon cache. It would be great that we find | 573 // see explorer rebuilding the icon cache. It would be great that we find |
580 // a better way to achieve this. | 574 // a better way to achieve this. |
581 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, | 575 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, |
582 NULL); | 576 NULL); |
583 } | 577 } |
584 return true; | 578 return true; |
585 } | 579 } |
586 | 580 |
587 bool CreatePlatformShortcuts( | 581 bool CreatePlatformShortcuts( |
588 const base::FilePath& web_app_path, | 582 const base::FilePath& web_app_path, |
589 const ShortcutInfo& shortcut_info, | 583 scoped_ptr<ShortcutInfo> shortcut_info, |
590 const extensions::FileHandlersInfo& file_handlers_info, | 584 const extensions::FileHandlersInfo& file_handlers_info, |
591 const ShortcutLocations& creation_locations, | 585 const ShortcutLocations& creation_locations, |
592 ShortcutCreationReason creation_reason) { | 586 ShortcutCreationReason creation_reason) { |
593 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 587 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
594 | 588 |
595 // Nothing to do on Windows for hidden apps. | 589 // Nothing to do on Windows for hidden apps. |
596 if (creation_locations.applications_menu_location == APP_MENU_LOCATION_HIDDEN) | 590 if (creation_locations.applications_menu_location == APP_MENU_LOCATION_HIDDEN) |
597 return true; | 591 return true; |
598 | 592 |
599 // Shortcut paths under which to create shortcuts. | 593 // Shortcut paths under which to create shortcuts. |
600 std::vector<base::FilePath> shortcut_paths = | 594 std::vector<base::FilePath> shortcut_paths = |
601 GetShortcutPaths(creation_locations); | 595 GetShortcutPaths(creation_locations); |
602 | 596 |
603 bool pin_to_taskbar = creation_locations.in_quick_launch_bar && | 597 bool pin_to_taskbar = creation_locations.in_quick_launch_bar && |
604 (base::win::GetVersion() >= base::win::VERSION_WIN7); | 598 (base::win::GetVersion() >= base::win::VERSION_WIN7); |
605 | 599 |
606 // Create/update the shortcut in the web app path for the "Pin To Taskbar" | 600 // Create/update the shortcut in the web app path for the "Pin To Taskbar" |
607 // option in Win7. We use the web app path shortcut because we will overwrite | 601 // option in Win7. We use the web app path shortcut because we will overwrite |
608 // it rather than appending unique numbers if the shortcut already exists. | 602 // it rather than appending unique numbers if the shortcut already exists. |
609 // This prevents pinned apps from having unique numbers in their names. | 603 // This prevents pinned apps from having unique numbers in their names. |
610 if (pin_to_taskbar) | 604 if (pin_to_taskbar) |
611 shortcut_paths.push_back(web_app_path); | 605 shortcut_paths.push_back(web_app_path); |
612 | 606 |
613 if (shortcut_paths.empty()) | 607 if (shortcut_paths.empty()) |
614 return false; | 608 return false; |
615 | 609 |
616 if (!CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths, | 610 if (!CreateShortcutsInPaths(web_app_path, *shortcut_info, shortcut_paths, |
617 creation_reason, NULL)) | 611 creation_reason, NULL)) |
618 return false; | 612 return false; |
619 | 613 |
620 if (pin_to_taskbar) { | 614 if (pin_to_taskbar) { |
621 base::FilePath file_name = GetSanitizedFileName(shortcut_info.title); | 615 base::FilePath file_name = GetSanitizedFileName(shortcut_info->title); |
622 // Use the web app path shortcut for pinning to avoid having unique numbers | 616 // Use the web app path shortcut for pinning to avoid having unique numbers |
623 // in the application name. | 617 // in the application name. |
624 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | 618 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). |
625 AddExtension(installer::kLnkExt); | 619 AddExtension(installer::kLnkExt); |
626 if (!base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str())) | 620 if (!base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str())) |
627 return false; | 621 return false; |
628 } | 622 } |
629 | 623 |
630 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 624 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
631 switches::kEnableAppsFileAssociations)) { | 625 switches::kEnableAppsFileAssociations)) { |
632 CreateFileAssociationsForApp( | 626 CreateFileAssociationsForApp( |
633 shortcut_info.extension_id, shortcut_info.title, | 627 shortcut_info->extension_id, shortcut_info->title, |
634 shortcut_info.profile_path, file_handlers_info); | 628 shortcut_info->profile_path, file_handlers_info); |
635 } | 629 } |
636 | 630 |
637 return true; | 631 return true; |
638 } | 632 } |
639 | 633 |
640 void UpdatePlatformShortcuts( | 634 void UpdatePlatformShortcuts( |
641 const base::FilePath& web_app_path, | 635 const base::FilePath& web_app_path, |
642 const base::string16& old_app_title, | 636 const base::string16& old_app_title, |
643 const ShortcutInfo& shortcut_info, | 637 scoped_ptr<ShortcutInfo> shortcut_info, |
644 const extensions::FileHandlersInfo& file_handlers_info) { | 638 const extensions::FileHandlersInfo& file_handlers_info) { |
645 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 639 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
646 | 640 |
647 // Generates file name to use with persisted ico and shortcut file. | 641 // Generates file name to use with persisted ico and shortcut file. |
648 base::FilePath file_name = | 642 base::FilePath file_name = |
649 web_app::internals::GetSanitizedFileName(shortcut_info.title); | 643 web_app::internals::GetSanitizedFileName(shortcut_info->title); |
650 | 644 |
651 if (old_app_title != shortcut_info.title) { | 645 if (old_app_title != shortcut_info->title) { |
652 // The app's title has changed. Delete all existing app shortcuts and | 646 // The app's title has changed. Delete all existing app shortcuts and |
653 // recreate them in any locations they already existed (but do not add them | 647 // recreate them in any locations they already existed (but do not add them |
654 // to locations where they do not currently exist). | 648 // to locations where they do not currently exist). |
655 bool was_pinned_to_taskbar; | 649 bool was_pinned_to_taskbar; |
656 std::vector<base::FilePath> shortcut_paths; | 650 std::vector<base::FilePath> shortcut_paths; |
657 GetShortcutLocationsAndDeleteShortcuts( | 651 GetShortcutLocationsAndDeleteShortcuts( |
658 web_app_path, shortcut_info.profile_path, old_app_title, | 652 web_app_path, shortcut_info->profile_path, old_app_title, |
659 &was_pinned_to_taskbar, &shortcut_paths); | 653 &was_pinned_to_taskbar, &shortcut_paths); |
660 CreateShortcutsInPaths(web_app_path, shortcut_info, shortcut_paths, | 654 CreateShortcutsInPaths(web_app_path, *shortcut_info, shortcut_paths, |
661 SHORTCUT_CREATION_BY_USER, NULL); | 655 SHORTCUT_CREATION_BY_USER, NULL); |
662 // If the shortcut was pinned to the taskbar, | 656 // If the shortcut was pinned to the taskbar, |
663 // GetShortcutLocationsAndDeleteShortcuts will have deleted it. In that | 657 // GetShortcutLocationsAndDeleteShortcuts will have deleted it. In that |
664 // case, re-pin it. | 658 // case, re-pin it. |
665 if (was_pinned_to_taskbar) { | 659 if (was_pinned_to_taskbar) { |
666 base::FilePath file_name = GetSanitizedFileName(shortcut_info.title); | 660 base::FilePath file_name = GetSanitizedFileName(shortcut_info->title); |
667 // Use the web app path shortcut for pinning to avoid having unique | 661 // Use the web app path shortcut for pinning to avoid having unique |
668 // numbers in the application name. | 662 // numbers in the application name. |
669 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). | 663 base::FilePath shortcut_to_pin = web_app_path.Append(file_name). |
670 AddExtension(installer::kLnkExt); | 664 AddExtension(installer::kLnkExt); |
671 base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str()); | 665 base::win::TaskbarPinShortcutLink(shortcut_to_pin.value().c_str()); |
672 } | 666 } |
673 } | 667 } |
674 | 668 |
675 // Update the icon if necessary. | 669 // Update the icon if necessary. |
676 base::FilePath icon_file = GetIconFilePath(web_app_path, shortcut_info.title); | 670 base::FilePath icon_file = |
677 CheckAndSaveIcon(icon_file, shortcut_info.favicon, true); | 671 GetIconFilePath(web_app_path, shortcut_info->title); |
| 672 CheckAndSaveIcon(icon_file, shortcut_info->favicon, true); |
678 } | 673 } |
679 | 674 |
680 void DeletePlatformShortcuts(const base::FilePath& web_app_path, | 675 void DeletePlatformShortcuts(const base::FilePath& web_app_path, |
681 const ShortcutInfo& shortcut_info) { | 676 scoped_ptr<ShortcutInfo> shortcut_info) { |
682 GetShortcutLocationsAndDeleteShortcuts( | 677 GetShortcutLocationsAndDeleteShortcuts(web_app_path, |
683 web_app_path, shortcut_info.profile_path, shortcut_info.title, NULL, | 678 shortcut_info->profile_path, |
684 NULL); | 679 shortcut_info->title, NULL, NULL); |
685 | 680 |
686 // If there are no more shortcuts in the Chrome Apps subdirectory, remove it. | 681 // If there are no more shortcuts in the Chrome Apps subdirectory, remove it. |
687 base::FilePath chrome_apps_dir; | 682 base::FilePath chrome_apps_dir; |
688 if (ShellUtil::GetShortcutPath( | 683 if (ShellUtil::GetShortcutPath( |
689 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, | 684 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, |
690 BrowserDistribution::GetDistribution(), | 685 BrowserDistribution::GetDistribution(), |
691 ShellUtil::CURRENT_USER, | 686 ShellUtil::CURRENT_USER, |
692 &chrome_apps_dir)) { | 687 &chrome_apps_dir)) { |
693 if (base::IsDirectoryEmpty(chrome_apps_dir)) | 688 if (base::IsDirectoryEmpty(chrome_apps_dir)) |
694 base::DeleteFile(chrome_apps_dir, false); | 689 base::DeleteFile(chrome_apps_dir, false); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 | 765 |
771 } // namespace internals | 766 } // namespace internals |
772 | 767 |
773 void UpdateShortcutForTabContents(content::WebContents* web_contents) { | 768 void UpdateShortcutForTabContents(content::WebContents* web_contents) { |
774 // UpdateShortcutWorker will delete itself when it's done. | 769 // UpdateShortcutWorker will delete itself when it's done. |
775 UpdateShortcutWorker* worker = new UpdateShortcutWorker(web_contents); | 770 UpdateShortcutWorker* worker = new UpdateShortcutWorker(web_contents); |
776 worker->Run(); | 771 worker->Run(); |
777 } | 772 } |
778 | 773 |
779 } // namespace web_app | 774 } // namespace web_app |
OLD | NEW |