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 <glib.h> | 8 #include <glib.h> |
9 #include <stdlib.h> | 9 #include <stdlib.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
(...skipping 22 matching lines...) Expand all Loading... | |
33 #include "base/strings/string_tokenizer.h" | 33 #include "base/strings/string_tokenizer.h" |
34 #include "base/strings/string_util.h" | 34 #include "base/strings/string_util.h" |
35 #include "base/strings/utf_string_conversions.h" | 35 #include "base/strings/utf_string_conversions.h" |
36 #include "base/threading/thread.h" | 36 #include "base/threading/thread.h" |
37 #include "base/threading/thread_restrictions.h" | 37 #include "base/threading/thread_restrictions.h" |
38 #include "build/build_config.h" | 38 #include "build/build_config.h" |
39 #include "chrome/browser/web_applications/web_app.h" | 39 #include "chrome/browser/web_applications/web_app.h" |
40 #include "chrome/common/chrome_constants.h" | 40 #include "chrome/common/chrome_constants.h" |
41 #include "chrome/common/chrome_version_info.h" | 41 #include "chrome/common/chrome_version_info.h" |
42 #include "content/public/browser/browser_thread.h" | 42 #include "content/public/browser/browser_thread.h" |
43 #include "grit/chromium_strings.h" | |
44 #include "ui/base/l10n/l10n_util.h" | |
43 #include "ui/gfx/image/image_family.h" | 45 #include "ui/gfx/image/image_family.h" |
44 #include "url/gurl.h" | 46 #include "url/gurl.h" |
45 | 47 |
46 using content::BrowserThread; | 48 using content::BrowserThread; |
47 | 49 |
48 namespace { | 50 namespace { |
49 | 51 |
50 // Helper to launch xdg scripts. We don't want them to ask any questions on the | 52 // Helper to launch xdg scripts. We don't want them to ask any questions on the |
51 // terminal etc. The function returns true if the utility launches and exits | 53 // terminal etc. The function returns true if the utility launches and exits |
52 // cleanly, in which case |exit_code| returns the utility's exit code. | 54 // cleanly, in which case |exit_code| returns the utility's exit code. |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
270 quoted += '\\'; | 272 quoted += '\\'; |
271 break; | 273 break; |
272 } | 274 } |
273 quoted += arg[i]; | 275 quoted += arg[i]; |
274 } | 276 } |
275 quoted += '"'; | 277 quoted += '"'; |
276 | 278 |
277 return quoted; | 279 return quoted; |
278 } | 280 } |
279 | 281 |
282 // TODO(calamity): replace with | |
283 // BrowserDistribution::GetStartMenuShortcutSubfolder() once | |
284 // BrowserDistribution is cross-platform. | |
285 // Gets the name of the Chrome Apps menu folder in which to place app shortcuts. | |
286 string16 GetAppShortcutsSubdirName() { | |
gab
2013/10/03 17:22:49
I would prefer having only a single copy of this m
calamity
2013/10/14 02:24:25
Done.
| |
287 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | |
288 if (channel == chrome::VersionInfo::CHANNEL_CANARY) | |
289 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY); | |
290 return l10n_util::GetStringUTF16(IDS_APP_SHORTCUTS_SUBDIR_NAME); | |
291 } | |
292 | |
280 const char kDesktopEntry[] = "Desktop Entry"; | 293 const char kDesktopEntry[] = "Desktop Entry"; |
281 | 294 |
282 const char kXdgOpenShebang[] = "#!/usr/bin/env xdg-open"; | 295 const char kXdgOpenShebang[] = "#!/usr/bin/env xdg-open"; |
283 | 296 |
284 const char kXdgSettings[] = "xdg-settings"; | 297 const char kXdgSettings[] = "xdg-settings"; |
285 const char kXdgSettingsDefaultBrowser[] = "default-web-browser"; | 298 const char kXdgSettingsDefaultBrowser[] = "default-web-browser"; |
286 const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler"; | 299 const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler"; |
287 | 300 |
288 const char kDirectoryFilename[] = "chrome-apps.directory"; | 301 const char kDirectoryFilename[] = "chrome-apps.directory"; |
289 | 302 |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 } | 601 } |
589 | 602 |
590 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( | 603 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( |
591 base::Environment* env, | 604 base::Environment* env, |
592 const base::FilePath& profile_path, | 605 const base::FilePath& profile_path, |
593 const std::string& extension_id) { | 606 const std::string& extension_id) { |
594 base::FilePath desktop_path; | 607 base::FilePath desktop_path; |
595 // If Get returns false, just leave desktop_path empty. | 608 // If Get returns false, just leave desktop_path empty. |
596 PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); | 609 PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); |
597 return GetExistingShortcutLocations(env, profile_path, extension_id, | 610 return GetExistingShortcutLocations(env, profile_path, extension_id, |
598 desktop_path); | 611 desktop_path); |
599 } | 612 } |
600 | 613 |
601 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( | 614 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( |
602 base::Environment* env, | 615 base::Environment* env, |
603 const base::FilePath& profile_path, | 616 const base::FilePath& profile_path, |
604 const std::string& extension_id, | 617 const std::string& extension_id, |
605 const base::FilePath& desktop_path) { | 618 const base::FilePath& desktop_path) { |
606 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
607 | 620 |
608 base::FilePath shortcut_filename = GetExtensionShortcutFilename( | 621 base::FilePath shortcut_filename = GetExtensionShortcutFilename( |
609 profile_path, extension_id); | 622 profile_path, extension_id); |
610 DCHECK(!shortcut_filename.empty()); | 623 DCHECK(!shortcut_filename.empty()); |
611 ShellIntegration::ShortcutLocations locations; | 624 ShellIntegration::ShortcutLocations locations; |
612 | 625 |
613 // Determine whether there is a shortcut on desktop. | 626 // Determine whether there is a shortcut on desktop. |
614 if (!desktop_path.empty()) { | 627 if (!desktop_path.empty()) { |
615 locations.on_desktop = | 628 locations.on_desktop = |
616 base::PathExists(desktop_path.Append(shortcut_filename)); | 629 base::PathExists(desktop_path.Append(shortcut_filename)); |
617 } | 630 } |
618 | 631 |
619 // Determine whether there is a shortcut in the applications directory. | 632 // Determine whether there is a shortcut in the applications directory. |
620 std::string shortcut_contents; | 633 std::string shortcut_contents; |
621 if (GetExistingShortcutContents(env, shortcut_filename, &shortcut_contents)) { | 634 if (GetExistingShortcutContents(env, shortcut_filename, &shortcut_contents)) { |
622 // Whether this counts as "hidden" or "in_applications_menu" depends on | 635 // Whether this counts as "hidden" or |
623 // whether it contains NoDisplay=true. | 636 // "in_applications_menu_chrome_apps_subdir" depends on whether it contains |
637 // NoDisplay=true. Since these shortcuts are for apps, they are always in | |
638 // the "Chrome Apps" directory. | |
624 if (GetNoDisplayFromDesktopFile(shortcut_contents)) | 639 if (GetNoDisplayFromDesktopFile(shortcut_contents)) |
625 locations.hidden = true; | 640 locations.hidden = true; |
626 else | 641 else |
627 locations.in_applications_menu = true; | 642 locations.in_applications_menu_chrome_apps_subdir = true; |
628 } | 643 } |
629 | 644 |
630 return locations; | 645 return locations; |
631 } | 646 } |
632 | 647 |
633 bool GetExistingShortcutContents(base::Environment* env, | 648 bool GetExistingShortcutContents(base::Environment* env, |
634 const base::FilePath& desktop_filename, | 649 const base::FilePath& desktop_filename, |
635 std::string* output) { | 650 std::string* output) { |
636 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
637 | 652 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 859 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
845 | 860 |
846 base::FilePath shortcut_filename; | 861 base::FilePath shortcut_filename; |
847 if (!shortcut_info.extension_id.empty()) { | 862 if (!shortcut_info.extension_id.empty()) { |
848 shortcut_filename = GetExtensionShortcutFilename( | 863 shortcut_filename = GetExtensionShortcutFilename( |
849 shortcut_info.profile_path, shortcut_info.extension_id); | 864 shortcut_info.profile_path, shortcut_info.extension_id); |
850 // For extensions we do not want duplicate shortcuts. So, delete any that | 865 // For extensions we do not want duplicate shortcuts. So, delete any that |
851 // already exist and replace them. | 866 // already exist and replace them. |
852 if (creation_locations.on_desktop) | 867 if (creation_locations.on_desktop) |
853 DeleteShortcutOnDesktop(shortcut_filename); | 868 DeleteShortcutOnDesktop(shortcut_filename); |
854 if (creation_locations.in_applications_menu || creation_locations.hidden) | 869 // The 'InApplicationsMenu()' and 'hidden' locations are actually the same |
870 // place ('applications'). | |
871 if (creation_locations.InApplicationsMenu() || creation_locations.hidden) | |
855 DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); | 872 DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); |
856 } else { | 873 } else { |
857 shortcut_filename = GetWebShortcutFilename(shortcut_info.url); | 874 shortcut_filename = GetWebShortcutFilename(shortcut_info.url); |
858 } | 875 } |
859 if (shortcut_filename.empty()) | 876 if (shortcut_filename.empty()) |
860 return false; | 877 return false; |
861 | 878 |
862 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); | 879 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); |
863 | 880 |
864 std::string app_name = | 881 std::string app_name = |
(...skipping 14 matching lines...) Expand all Loading... | |
879 shortcut_info.url, | 896 shortcut_info.url, |
880 shortcut_info.extension_id, | 897 shortcut_info.extension_id, |
881 shortcut_info.extension_path, | 898 shortcut_info.extension_path, |
882 shortcut_info.title, | 899 shortcut_info.title, |
883 icon_name, | 900 icon_name, |
884 shortcut_info.profile_path, | 901 shortcut_info.profile_path, |
885 false); | 902 false); |
886 success = CreateShortcutOnDesktop(shortcut_filename, contents); | 903 success = CreateShortcutOnDesktop(shortcut_filename, contents); |
887 } | 904 } |
888 | 905 |
889 // The 'in_applications_menu' and 'hidden' locations are actually the same | 906 if (creation_locations.InApplicationsMenu() || creation_locations.hidden) { |
890 // place ('applications'). | |
891 if (creation_locations.in_applications_menu || creation_locations.hidden) { | |
892 base::FilePath directory_filename; | 907 base::FilePath directory_filename; |
893 std::string directory_contents; | 908 std::string directory_contents; |
894 if (!creation_locations.applications_menu_subdir.empty()) { | 909 if (creation_locations.in_applications_menu_chrome_apps_subdir) { |
895 directory_filename = base::FilePath(kDirectoryFilename); | 910 directory_filename = base::FilePath(kDirectoryFilename); |
896 directory_contents = ShellIntegrationLinux::GetDirectoryFileContents( | 911 directory_contents = ShellIntegrationLinux::GetDirectoryFileContents( |
897 creation_locations.applications_menu_subdir, ""); | 912 GetAppShortcutsSubdirName(), ""); |
898 } | 913 } |
899 // Set NoDisplay=true if hidden but not in_applications_menu. This will hide | 914 // Set NoDisplay=true if hidden but not InApplicationsMenu(). This will hide |
900 // the application from user-facing menus. | 915 // the application from user-facing menus. |
901 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( | 916 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( |
902 chrome_exe_path, | 917 chrome_exe_path, |
903 app_name, | 918 app_name, |
904 shortcut_info.url, | 919 shortcut_info.url, |
905 shortcut_info.extension_id, | 920 shortcut_info.extension_id, |
906 shortcut_info.extension_path, | 921 shortcut_info.extension_path, |
907 shortcut_info.title, | 922 shortcut_info.title, |
908 icon_name, | 923 icon_name, |
909 shortcut_info.profile_path, | 924 shortcut_info.profile_path, |
910 !creation_locations.in_applications_menu); | 925 !creation_locations.InApplicationsMenu()); |
911 success = CreateShortcutInApplicationsMenu( | 926 success = CreateShortcutInApplicationsMenu( |
912 shortcut_filename, contents, directory_filename, directory_contents) && | 927 shortcut_filename, contents, directory_filename, directory_contents) && |
913 success; | 928 success; |
914 } | 929 } |
915 | 930 |
916 return success; | 931 return success; |
917 } | 932 } |
918 | 933 |
919 void DeleteDesktopShortcuts(const base::FilePath& profile_path, | 934 void DeleteDesktopShortcuts(const base::FilePath& profile_path, |
920 const std::string& extension_id) { | 935 const std::string& extension_id) { |
921 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 936 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
922 | 937 |
923 base::FilePath shortcut_filename = GetExtensionShortcutFilename( | 938 base::FilePath shortcut_filename = GetExtensionShortcutFilename( |
924 profile_path, extension_id); | 939 profile_path, extension_id); |
925 DCHECK(!shortcut_filename.empty()); | 940 DCHECK(!shortcut_filename.empty()); |
926 | 941 |
927 DeleteShortcutOnDesktop(shortcut_filename); | 942 DeleteShortcutOnDesktop(shortcut_filename); |
928 // Delete shortcuts from |kDirectoryFilename|. | 943 // Delete shortcuts from |kDirectoryFilename|. |
929 // Note that it is possible that shortcuts were not created in the Chrome Apps | 944 // Note that it is possible that shortcuts were not created in the Chrome Apps |
930 // directory (depending on the value of |applications_menu_subdir| when they | 945 // directory. It doesn't matter: this will still delete the shortcut even if |
931 // were created). It doesn't matter: this will still delete the shortcut even | 946 // it isn't in the directory. |
932 // if it isn't in the directory. | |
933 DeleteShortcutInApplicationsMenu(shortcut_filename, | 947 DeleteShortcutInApplicationsMenu(shortcut_filename, |
934 base::FilePath(kDirectoryFilename)); | 948 base::FilePath(kDirectoryFilename)); |
935 } | 949 } |
936 | 950 |
937 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) { | 951 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) { |
938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 952 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
939 | 953 |
940 scoped_ptr<base::Environment> env(base::Environment::Create()); | 954 scoped_ptr<base::Environment> env(base::Environment::Create()); |
941 | 955 |
942 // Delete shortcuts from Desktop. | 956 // Delete shortcuts from Desktop. |
(...skipping 17 matching lines...) Expand all Loading... | |
960 for (std::vector<base::FilePath>::const_iterator it = | 974 for (std::vector<base::FilePath>::const_iterator it = |
961 shortcut_filenames_app_menu.begin(); | 975 shortcut_filenames_app_menu.begin(); |
962 it != shortcut_filenames_app_menu.end(); ++it) { | 976 it != shortcut_filenames_app_menu.end(); ++it) { |
963 DeleteShortcutInApplicationsMenu(*it, | 977 DeleteShortcutInApplicationsMenu(*it, |
964 base::FilePath(kDirectoryFilename)); | 978 base::FilePath(kDirectoryFilename)); |
965 } | 979 } |
966 } | 980 } |
967 } | 981 } |
968 | 982 |
969 } // namespace ShellIntegrationLinux | 983 } // namespace ShellIntegrationLinux |
OLD | NEW |