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/shell_integration_linux.h" | 5 #include "chrome/browser/shell_integration_linux.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include <memory> | 10 #include <memory> |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 #include "base/threading/thread.h" | 43 #include "base/threading/thread.h" |
44 #include "base/threading/thread_restrictions.h" | 44 #include "base/threading/thread_restrictions.h" |
45 #include "build/build_config.h" | 45 #include "build/build_config.h" |
46 #include "chrome/browser/shell_integration.h" | 46 #include "chrome/browser/shell_integration.h" |
47 #include "chrome/common/channel_info.h" | 47 #include "chrome/common/channel_info.h" |
48 #include "chrome/common/chrome_constants.h" | 48 #include "chrome/common/chrome_constants.h" |
49 #include "chrome/common/chrome_switches.h" | 49 #include "chrome/common/chrome_switches.h" |
50 #include "chrome/common/features.h" | 50 #include "chrome/common/features.h" |
51 #include "chrome/grit/chrome_unscaled_resources.h" | 51 #include "chrome/grit/chrome_unscaled_resources.h" |
52 #include "components/version_info/version_info.h" | 52 #include "components/version_info/version_info.h" |
53 #include "content/public/browser/browser_thread.h" | |
54 #include "ui/base/resource/resource_bundle.h" | 53 #include "ui/base/resource/resource_bundle.h" |
55 #include "ui/gfx/image/image_family.h" | 54 #include "ui/gfx/image/image_family.h" |
56 #include "url/gurl.h" | 55 #include "url/gurl.h" |
57 | 56 |
58 using content::BrowserThread; | |
59 | |
60 namespace shell_integration { | 57 namespace shell_integration { |
61 | 58 |
62 namespace { | 59 namespace { |
63 | 60 |
64 // Helper to launch xdg scripts. We don't want them to ask any questions on the | 61 // Helper to launch xdg scripts. We don't want them to ask any questions on the |
65 // terminal etc. The function returns true if the utility launches and exits | 62 // terminal etc. The function returns true if the utility launches and exits |
66 // cleanly, in which case |exit_code| returns the utility's exit code. | 63 // cleanly, in which case |exit_code| returns the utility's exit code. |
67 bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) { | 64 bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) { |
68 // xdg-settings internally runs xdg-mime, which uses mv to move newly-created | 65 // xdg-settings internally runs xdg-mime, which uses mv to move newly-created |
69 // files on top of originals after making changes to them. In the event that | 66 // files on top of originals after making changes to them. In the event that |
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 | 555 |
559 // Just return the name of the executable path for Chrome. | 556 // Just return the name of the executable path for Chrome. |
560 base::FilePath chrome_exe_path; | 557 base::FilePath chrome_exe_path; |
561 PathService::Get(base::FILE_EXE, &chrome_exe_path); | 558 PathService::Get(base::FILE_EXE, &chrome_exe_path); |
562 return chrome_exe_path; | 559 return chrome_exe_path; |
563 } | 560 } |
564 | 561 |
565 } // namespace | 562 } // namespace |
566 | 563 |
567 base::FilePath GetDataWriteLocation(base::Environment* env) { | 564 base::FilePath GetDataWriteLocation(base::Environment* env) { |
568 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 565 base::ThreadRestrictions::AssertIOAllowed(); |
569 | 566 |
570 return base::nix::GetXDGDirectory(env, "XDG_DATA_HOME", ".local/share"); | 567 return base::nix::GetXDGDirectory(env, "XDG_DATA_HOME", ".local/share"); |
571 } | 568 } |
572 | 569 |
573 std::vector<base::FilePath> GetDataSearchLocations(base::Environment* env) { | 570 std::vector<base::FilePath> GetDataSearchLocations(base::Environment* env) { |
574 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 571 base::ThreadRestrictions::AssertIOAllowed(); |
575 | 572 |
576 std::vector<base::FilePath> search_paths; | 573 std::vector<base::FilePath> search_paths; |
577 base::FilePath write_location = GetDataWriteLocation(env); | 574 base::FilePath write_location = GetDataWriteLocation(env); |
578 search_paths.push_back(write_location); | 575 search_paths.push_back(write_location); |
579 | 576 |
580 std::string xdg_data_dirs; | 577 std::string xdg_data_dirs; |
581 if (env->GetVar("XDG_DATA_DIRS", &xdg_data_dirs) && !xdg_data_dirs.empty()) { | 578 if (env->GetVar("XDG_DATA_DIRS", &xdg_data_dirs) && !xdg_data_dirs.empty()) { |
582 base::StringTokenizer tokenizer(xdg_data_dirs, ":"); | 579 base::StringTokenizer tokenizer(xdg_data_dirs, ":"); |
583 while (tokenizer.GetNext()) { | 580 while (tokenizer.GetNext()) { |
584 base::FilePath data_dir(tokenizer.token()); | 581 base::FilePath data_dir(tokenizer.token()); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); | 672 PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); |
676 return GetExistingShortcutLocations(env, profile_path, extension_id, | 673 return GetExistingShortcutLocations(env, profile_path, extension_id, |
677 desktop_path); | 674 desktop_path); |
678 } | 675 } |
679 | 676 |
680 web_app::ShortcutLocations GetExistingShortcutLocations( | 677 web_app::ShortcutLocations GetExistingShortcutLocations( |
681 base::Environment* env, | 678 base::Environment* env, |
682 const base::FilePath& profile_path, | 679 const base::FilePath& profile_path, |
683 const std::string& extension_id, | 680 const std::string& extension_id, |
684 const base::FilePath& desktop_path) { | 681 const base::FilePath& desktop_path) { |
685 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 682 base::ThreadRestrictions::AssertIOAllowed(); |
686 | 683 |
687 base::FilePath shortcut_filename = GetExtensionShortcutFilename( | 684 base::FilePath shortcut_filename = GetExtensionShortcutFilename( |
688 profile_path, extension_id); | 685 profile_path, extension_id); |
689 DCHECK(!shortcut_filename.empty()); | 686 DCHECK(!shortcut_filename.empty()); |
690 web_app::ShortcutLocations locations; | 687 web_app::ShortcutLocations locations; |
691 | 688 |
692 // Determine whether there is a shortcut on desktop. | 689 // Determine whether there is a shortcut on desktop. |
693 if (!desktop_path.empty()) { | 690 if (!desktop_path.empty()) { |
694 locations.on_desktop = | 691 locations.on_desktop = |
695 base::PathExists(desktop_path.Append(shortcut_filename)); | 692 base::PathExists(desktop_path.Append(shortcut_filename)); |
(...skipping 10 matching lines...) Expand all Loading... |
706 ? web_app::APP_MENU_LOCATION_HIDDEN | 703 ? web_app::APP_MENU_LOCATION_HIDDEN |
707 : web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS; | 704 : web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS; |
708 } | 705 } |
709 | 706 |
710 return locations; | 707 return locations; |
711 } | 708 } |
712 | 709 |
713 bool GetExistingShortcutContents(base::Environment* env, | 710 bool GetExistingShortcutContents(base::Environment* env, |
714 const base::FilePath& desktop_filename, | 711 const base::FilePath& desktop_filename, |
715 std::string* output) { | 712 std::string* output) { |
716 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 713 base::ThreadRestrictions::AssertIOAllowed(); |
717 | 714 |
718 std::vector<base::FilePath> search_paths = GetDataSearchLocations(env); | 715 std::vector<base::FilePath> search_paths = GetDataSearchLocations(env); |
719 | 716 |
720 for (std::vector<base::FilePath>::const_iterator i = search_paths.begin(); | 717 for (std::vector<base::FilePath>::const_iterator i = search_paths.begin(); |
721 i != search_paths.end(); ++i) { | 718 i != search_paths.end(); ++i) { |
722 base::FilePath path = i->Append("applications").Append(desktop_filename); | 719 base::FilePath path = i->Append("applications").Append(desktop_filename); |
723 VLOG(1) << "Looking for desktop file in " << path.value(); | 720 VLOG(1) << "Looking for desktop file in " << path.value(); |
724 if (base::PathExists(path)) { | 721 if (base::PathExists(path)) { |
725 VLOG(1) << "Found desktop file at " << path.value(); | 722 VLOG(1) << "Found desktop file at " << path.value(); |
726 return base::ReadFileToString(path, output); | 723 return base::ReadFileToString(path, output); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
767 base::i18n::ReplaceIllegalCharactersInPath(&filename, '_'); | 764 base::i18n::ReplaceIllegalCharactersInPath(&filename, '_'); |
768 // Spaces in filenames break xdg-desktop-menu | 765 // Spaces in filenames break xdg-desktop-menu |
769 // (see https://bugs.freedesktop.org/show_bug.cgi?id=66605). | 766 // (see https://bugs.freedesktop.org/show_bug.cgi?id=66605). |
770 base::ReplaceChars(filename, " ", "_", &filename); | 767 base::ReplaceChars(filename, " ", "_", &filename); |
771 return base::FilePath(filename.append(".desktop")); | 768 return base::FilePath(filename.append(".desktop")); |
772 } | 769 } |
773 | 770 |
774 std::vector<base::FilePath> GetExistingProfileShortcutFilenames( | 771 std::vector<base::FilePath> GetExistingProfileShortcutFilenames( |
775 const base::FilePath& profile_path, | 772 const base::FilePath& profile_path, |
776 const base::FilePath& directory) { | 773 const base::FilePath& directory) { |
777 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 774 base::ThreadRestrictions::AssertIOAllowed(); |
778 | 775 |
779 // Use a prefix, because xdg-desktop-menu requires it. | 776 // Use a prefix, because xdg-desktop-menu requires it. |
780 std::string prefix(chrome::kBrowserProcessExecutableName); | 777 std::string prefix(chrome::kBrowserProcessExecutableName); |
781 prefix.append("-"); | 778 prefix.append("-"); |
782 std::string suffix("-"); | 779 std::string suffix("-"); |
783 suffix.append(profile_path.BaseName().value()); | 780 suffix.append(profile_path.BaseName().value()); |
784 base::i18n::ReplaceIllegalCharactersInPath(&suffix, '_'); | 781 base::i18n::ReplaceIllegalCharactersInPath(&suffix, '_'); |
785 // Spaces in filenames break xdg-desktop-menu | 782 // Spaces in filenames break xdg-desktop-menu |
786 // (see https://bugs.freedesktop.org/show_bug.cgi?id=66605). | 783 // (see https://bugs.freedesktop.org/show_bug.cgi?id=66605). |
787 base::ReplaceChars(suffix, " ", "_", &suffix); | 784 base::ReplaceChars(suffix, " ", "_", &suffix); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
932 return output_buffer; | 929 return output_buffer; |
933 #else | 930 #else |
934 NOTIMPLEMENTED(); | 931 NOTIMPLEMENTED(); |
935 return std::string(); | 932 return std::string(); |
936 #endif | 933 #endif |
937 } | 934 } |
938 | 935 |
939 bool CreateDesktopShortcut( | 936 bool CreateDesktopShortcut( |
940 const web_app::ShortcutInfo& shortcut_info, | 937 const web_app::ShortcutInfo& shortcut_info, |
941 const web_app::ShortcutLocations& creation_locations) { | 938 const web_app::ShortcutLocations& creation_locations) { |
942 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 939 base::ThreadRestrictions::AssertIOAllowed(); |
943 | 940 |
944 base::FilePath shortcut_filename; | 941 base::FilePath shortcut_filename; |
945 if (!shortcut_info.extension_id.empty()) { | 942 if (!shortcut_info.extension_id.empty()) { |
946 shortcut_filename = GetExtensionShortcutFilename( | 943 shortcut_filename = GetExtensionShortcutFilename( |
947 shortcut_info.profile_path, shortcut_info.extension_id); | 944 shortcut_info.profile_path, shortcut_info.extension_id); |
948 // For extensions we do not want duplicate shortcuts. So, delete any that | 945 // For extensions we do not want duplicate shortcuts. So, delete any that |
949 // already exist and replace them. | 946 // already exist and replace them. |
950 if (creation_locations.on_desktop) | 947 if (creation_locations.on_desktop) |
951 DeleteShortcutOnDesktop(shortcut_filename); | 948 DeleteShortcutOnDesktop(shortcut_filename); |
952 | 949 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 shortcut_filename, contents, directory_filename, directory_contents) && | 1022 shortcut_filename, contents, directory_filename, directory_contents) && |
1026 success; | 1023 success; |
1027 | 1024 |
1028 return success; | 1025 return success; |
1029 } | 1026 } |
1030 | 1027 |
1031 #if BUILDFLAG(ENABLE_APP_LIST) | 1028 #if BUILDFLAG(ENABLE_APP_LIST) |
1032 bool CreateAppListDesktopShortcut( | 1029 bool CreateAppListDesktopShortcut( |
1033 const std::string& wm_class, | 1030 const std::string& wm_class, |
1034 const std::string& title) { | 1031 const std::string& title) { |
1035 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 1032 base::ThreadRestrictions::AssertIOAllowed(); |
1036 | 1033 |
1037 base::FilePath desktop_name(kAppListDesktopName); | 1034 base::FilePath desktop_name(kAppListDesktopName); |
1038 base::FilePath shortcut_filename = desktop_name.AddExtension("desktop"); | 1035 base::FilePath shortcut_filename = desktop_name.AddExtension("desktop"); |
1039 | 1036 |
1040 // We do not want duplicate shortcuts. Delete any that already exist and | 1037 // We do not want duplicate shortcuts. Delete any that already exist and |
1041 // replace them. | 1038 // replace them. |
1042 DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); | 1039 DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); |
1043 | 1040 |
1044 base::FilePath chrome_exe_path = GetChromeExePath(); | 1041 base::FilePath chrome_exe_path = GetChromeExePath(); |
1045 if (chrome_exe_path.empty()) { | 1042 if (chrome_exe_path.empty()) { |
(...skipping 19 matching lines...) Expand all Loading... |
1065 icon_name, | 1062 icon_name, |
1066 kAppListCategories, | 1063 kAppListCategories, |
1067 false); | 1064 false); |
1068 return CreateShortcutInApplicationsMenu( | 1065 return CreateShortcutInApplicationsMenu( |
1069 shortcut_filename, contents, base::FilePath(), ""); | 1066 shortcut_filename, contents, base::FilePath(), ""); |
1070 } | 1067 } |
1071 #endif | 1068 #endif |
1072 | 1069 |
1073 void DeleteDesktopShortcuts(const base::FilePath& profile_path, | 1070 void DeleteDesktopShortcuts(const base::FilePath& profile_path, |
1074 const std::string& extension_id) { | 1071 const std::string& extension_id) { |
1075 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 1072 base::ThreadRestrictions::AssertIOAllowed(); |
1076 | 1073 |
1077 base::FilePath shortcut_filename = GetExtensionShortcutFilename( | 1074 base::FilePath shortcut_filename = GetExtensionShortcutFilename( |
1078 profile_path, extension_id); | 1075 profile_path, extension_id); |
1079 DCHECK(!shortcut_filename.empty()); | 1076 DCHECK(!shortcut_filename.empty()); |
1080 | 1077 |
1081 DeleteShortcutOnDesktop(shortcut_filename); | 1078 DeleteShortcutOnDesktop(shortcut_filename); |
1082 // Delete shortcuts from |kDirectoryFilename|. | 1079 // Delete shortcuts from |kDirectoryFilename|. |
1083 // Note that it is possible that shortcuts were not created in the Chrome Apps | 1080 // Note that it is possible that shortcuts were not created in the Chrome Apps |
1084 // directory. It doesn't matter: this will still delete the shortcut even if | 1081 // directory. It doesn't matter: this will still delete the shortcut even if |
1085 // it isn't in the directory. | 1082 // it isn't in the directory. |
1086 DeleteShortcutInApplicationsMenu(shortcut_filename, | 1083 DeleteShortcutInApplicationsMenu(shortcut_filename, |
1087 base::FilePath(kDirectoryFilename)); | 1084 base::FilePath(kDirectoryFilename)); |
1088 } | 1085 } |
1089 | 1086 |
1090 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) { | 1087 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) { |
1091 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 1088 base::ThreadRestrictions::AssertIOAllowed(); |
1092 | 1089 |
1093 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 1090 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
1094 | 1091 |
1095 // Delete shortcuts from Desktop. | 1092 // Delete shortcuts from Desktop. |
1096 base::FilePath desktop_path; | 1093 base::FilePath desktop_path; |
1097 if (PathService::Get(base::DIR_USER_DESKTOP, &desktop_path)) { | 1094 if (PathService::Get(base::DIR_USER_DESKTOP, &desktop_path)) { |
1098 std::vector<base::FilePath> shortcut_filenames_desktop = | 1095 std::vector<base::FilePath> shortcut_filenames_desktop = |
1099 GetExistingProfileShortcutFilenames(profile_path, desktop_path); | 1096 GetExistingProfileShortcutFilenames(profile_path, desktop_path); |
1100 for (const auto& shortcut : shortcut_filenames_desktop) { | 1097 for (const auto& shortcut : shortcut_filenames_desktop) { |
1101 DeleteShortcutOnDesktop(shortcut); | 1098 DeleteShortcutOnDesktop(shortcut); |
1102 } | 1099 } |
1103 } | 1100 } |
1104 | 1101 |
1105 // Delete shortcuts from |kDirectoryFilename|. | 1102 // Delete shortcuts from |kDirectoryFilename|. |
1106 base::FilePath applications_menu = GetDataWriteLocation(env.get()); | 1103 base::FilePath applications_menu = GetDataWriteLocation(env.get()); |
1107 applications_menu = applications_menu.AppendASCII("applications"); | 1104 applications_menu = applications_menu.AppendASCII("applications"); |
1108 std::vector<base::FilePath> shortcut_filenames_app_menu = | 1105 std::vector<base::FilePath> shortcut_filenames_app_menu = |
1109 GetExistingProfileShortcutFilenames(profile_path, applications_menu); | 1106 GetExistingProfileShortcutFilenames(profile_path, applications_menu); |
1110 for (const auto& menu : shortcut_filenames_app_menu) { | 1107 for (const auto& menu : shortcut_filenames_app_menu) { |
1111 DeleteShortcutInApplicationsMenu(menu, base::FilePath(kDirectoryFilename)); | 1108 DeleteShortcutInApplicationsMenu(menu, base::FilePath(kDirectoryFilename)); |
1112 } | 1109 } |
1113 } | 1110 } |
1114 | 1111 |
1115 } // namespace shell_integration_linux | 1112 } // namespace shell_integration_linux |
OLD | NEW |