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() { |
| 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 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 } | 597 } |
585 | 598 |
586 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( | 599 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( |
587 base::Environment* env, | 600 base::Environment* env, |
588 const base::FilePath& profile_path, | 601 const base::FilePath& profile_path, |
589 const std::string& extension_id) { | 602 const std::string& extension_id) { |
590 base::FilePath desktop_path; | 603 base::FilePath desktop_path; |
591 // If Get returns false, just leave desktop_path empty. | 604 // If Get returns false, just leave desktop_path empty. |
592 PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); | 605 PathService::Get(base::DIR_USER_DESKTOP, &desktop_path); |
593 return GetExistingShortcutLocations(env, profile_path, extension_id, | 606 return GetExistingShortcutLocations(env, profile_path, extension_id, |
594 desktop_path); | 607 desktop_path); |
595 } | 608 } |
596 | 609 |
597 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( | 610 ShellIntegration::ShortcutLocations GetExistingShortcutLocations( |
598 base::Environment* env, | 611 base::Environment* env, |
599 const base::FilePath& profile_path, | 612 const base::FilePath& profile_path, |
600 const std::string& extension_id, | 613 const std::string& extension_id, |
601 const base::FilePath& desktop_path) { | 614 const base::FilePath& desktop_path) { |
602 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
603 | 616 |
604 base::FilePath shortcut_filename = GetExtensionShortcutFilename( | 617 base::FilePath shortcut_filename = GetExtensionShortcutFilename( |
605 profile_path, extension_id); | 618 profile_path, extension_id); |
606 DCHECK(!shortcut_filename.empty()); | 619 DCHECK(!shortcut_filename.empty()); |
607 ShellIntegration::ShortcutLocations locations; | 620 ShellIntegration::ShortcutLocations locations; |
608 | 621 |
609 // Determine whether there is a shortcut on desktop. | 622 // Determine whether there is a shortcut on desktop. |
610 if (!desktop_path.empty()) { | 623 if (!desktop_path.empty()) { |
611 locations.on_desktop = | 624 locations.on_desktop = |
612 base::PathExists(desktop_path.Append(shortcut_filename)); | 625 base::PathExists(desktop_path.Append(shortcut_filename)); |
613 } | 626 } |
614 | 627 |
615 // Determine whether there is a shortcut in the applications directory. | 628 // Determine whether there is a shortcut in the applications directory. |
616 std::string shortcut_contents; | 629 std::string shortcut_contents; |
617 if (GetExistingShortcutContents(env, shortcut_filename, &shortcut_contents)) { | 630 if (GetExistingShortcutContents(env, shortcut_filename, &shortcut_contents)) { |
618 // Whether this counts as "hidden" or "in_applications_menu" depends on | 631 // Whether this counts as "hidden" or |
619 // whether it contains NoDisplay=true. | 632 // "in_applications_menu_chrome_apps_subdir" depends on whether it contains |
| 633 // NoDisplay=true. Since these shortcuts are for apps, they are always in |
| 634 // the "Chrome Apps" directory. |
620 if (GetNoDisplayFromDesktopFile(shortcut_contents)) | 635 if (GetNoDisplayFromDesktopFile(shortcut_contents)) |
621 locations.hidden = true; | 636 locations.hidden = true; |
622 else | 637 else |
623 locations.in_applications_menu = true; | 638 locations.in_applications_menu_chrome_apps_subdir = true; |
624 } | 639 } |
625 | 640 |
626 return locations; | 641 return locations; |
627 } | 642 } |
628 | 643 |
629 bool GetExistingShortcutContents(base::Environment* env, | 644 bool GetExistingShortcutContents(base::Environment* env, |
630 const base::FilePath& desktop_filename, | 645 const base::FilePath& desktop_filename, |
631 std::string* output) { | 646 std::string* output) { |
632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
633 | 648 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 855 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
841 | 856 |
842 base::FilePath shortcut_filename; | 857 base::FilePath shortcut_filename; |
843 if (!shortcut_info.extension_id.empty()) { | 858 if (!shortcut_info.extension_id.empty()) { |
844 shortcut_filename = GetExtensionShortcutFilename( | 859 shortcut_filename = GetExtensionShortcutFilename( |
845 shortcut_info.profile_path, shortcut_info.extension_id); | 860 shortcut_info.profile_path, shortcut_info.extension_id); |
846 // For extensions we do not want duplicate shortcuts. So, delete any that | 861 // For extensions we do not want duplicate shortcuts. So, delete any that |
847 // already exist and replace them. | 862 // already exist and replace them. |
848 if (creation_locations.on_desktop) | 863 if (creation_locations.on_desktop) |
849 DeleteShortcutOnDesktop(shortcut_filename); | 864 DeleteShortcutOnDesktop(shortcut_filename); |
850 if (creation_locations.in_applications_menu || creation_locations.hidden) | 865 // The 'InApplicationsMenu()' and 'hidden' locations are actually the same |
| 866 // place ('applications'). |
| 867 if (creation_locations.InApplicationsMenu() || creation_locations.hidden) |
851 DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); | 868 DeleteShortcutInApplicationsMenu(shortcut_filename, base::FilePath()); |
852 } else { | 869 } else { |
853 shortcut_filename = GetWebShortcutFilename(shortcut_info.url); | 870 shortcut_filename = GetWebShortcutFilename(shortcut_info.url); |
854 } | 871 } |
855 if (shortcut_filename.empty()) | 872 if (shortcut_filename.empty()) |
856 return false; | 873 return false; |
857 | 874 |
858 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); | 875 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); |
859 | 876 |
860 std::string app_name = | 877 std::string app_name = |
(...skipping 14 matching lines...) Expand all Loading... |
875 shortcut_info.url, | 892 shortcut_info.url, |
876 shortcut_info.extension_id, | 893 shortcut_info.extension_id, |
877 shortcut_info.extension_path, | 894 shortcut_info.extension_path, |
878 shortcut_info.title, | 895 shortcut_info.title, |
879 icon_name, | 896 icon_name, |
880 shortcut_info.profile_path, | 897 shortcut_info.profile_path, |
881 false); | 898 false); |
882 success = CreateShortcutOnDesktop(shortcut_filename, contents); | 899 success = CreateShortcutOnDesktop(shortcut_filename, contents); |
883 } | 900 } |
884 | 901 |
885 // The 'in_applications_menu' and 'hidden' locations are actually the same | 902 if (creation_locations.InApplicationsMenu() || creation_locations.hidden) { |
886 // place ('applications'). | |
887 if (creation_locations.in_applications_menu || creation_locations.hidden) { | |
888 base::FilePath directory_filename; | 903 base::FilePath directory_filename; |
889 std::string directory_contents; | 904 std::string directory_contents; |
890 if (!creation_locations.applications_menu_subdir.empty()) { | 905 if (creation_locations.in_applications_menu_chrome_apps_subdir) { |
891 directory_filename = base::FilePath(kDirectoryFilename); | 906 directory_filename = base::FilePath(kDirectoryFilename); |
892 directory_contents = ShellIntegrationLinux::GetDirectoryFileContents( | 907 directory_contents = ShellIntegrationLinux::GetDirectoryFileContents( |
893 creation_locations.applications_menu_subdir, ""); | 908 GetAppShortcutsSubdirName(), ""); |
894 } | 909 } |
895 // Set NoDisplay=true if hidden but not in_applications_menu. This will hide | 910 // Set NoDisplay=true if hidden but not InApplicationsMenu(). This will hide |
896 // the application from user-facing menus. | 911 // the application from user-facing menus. |
897 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( | 912 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( |
898 chrome_exe_path, | 913 chrome_exe_path, |
899 app_name, | 914 app_name, |
900 shortcut_info.url, | 915 shortcut_info.url, |
901 shortcut_info.extension_id, | 916 shortcut_info.extension_id, |
902 shortcut_info.extension_path, | 917 shortcut_info.extension_path, |
903 shortcut_info.title, | 918 shortcut_info.title, |
904 icon_name, | 919 icon_name, |
905 shortcut_info.profile_path, | 920 shortcut_info.profile_path, |
906 !creation_locations.in_applications_menu); | 921 !creation_locations.InApplicationsMenu()); |
907 success = CreateShortcutInApplicationsMenu( | 922 success = CreateShortcutInApplicationsMenu( |
908 shortcut_filename, contents, directory_filename, directory_contents) && | 923 shortcut_filename, contents, directory_filename, directory_contents) && |
909 success; | 924 success; |
910 } | 925 } |
911 | 926 |
912 return success; | 927 return success; |
913 } | 928 } |
914 | 929 |
915 void DeleteDesktopShortcuts(const base::FilePath& profile_path, | 930 void DeleteDesktopShortcuts(const base::FilePath& profile_path, |
916 const std::string& extension_id) { | 931 const std::string& extension_id) { |
917 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 932 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
918 | 933 |
919 base::FilePath shortcut_filename = GetExtensionShortcutFilename( | 934 base::FilePath shortcut_filename = GetExtensionShortcutFilename( |
920 profile_path, extension_id); | 935 profile_path, extension_id); |
921 DCHECK(!shortcut_filename.empty()); | 936 DCHECK(!shortcut_filename.empty()); |
922 | 937 |
923 DeleteShortcutOnDesktop(shortcut_filename); | 938 DeleteShortcutOnDesktop(shortcut_filename); |
924 // Delete shortcuts from |kDirectoryFilename|. | 939 // Delete shortcuts from |kDirectoryFilename|. |
925 // Note that it is possible that shortcuts were not created in the Chrome Apps | 940 // Note that it is possible that shortcuts were not created in the Chrome Apps |
926 // directory (depending on the value of |applications_menu_subdir| when they | 941 // directory. It doesn't matter: this will still delete the shortcut even if |
927 // were created). It doesn't matter: this will still delete the shortcut even | 942 // it isn't in the directory. |
928 // if it isn't in the directory. | |
929 DeleteShortcutInApplicationsMenu(shortcut_filename, | 943 DeleteShortcutInApplicationsMenu(shortcut_filename, |
930 base::FilePath(kDirectoryFilename)); | 944 base::FilePath(kDirectoryFilename)); |
931 } | 945 } |
932 | 946 |
933 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) { | 947 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) { |
934 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 948 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
935 | 949 |
936 scoped_ptr<base::Environment> env(base::Environment::Create()); | 950 scoped_ptr<base::Environment> env(base::Environment::Create()); |
937 | 951 |
938 // Delete shortcuts from Desktop. | 952 // Delete shortcuts from Desktop. |
(...skipping 17 matching lines...) Expand all Loading... |
956 for (std::vector<base::FilePath>::const_iterator it = | 970 for (std::vector<base::FilePath>::const_iterator it = |
957 shortcut_filenames_app_menu.begin(); | 971 shortcut_filenames_app_menu.begin(); |
958 it != shortcut_filenames_app_menu.end(); ++it) { | 972 it != shortcut_filenames_app_menu.end(); ++it) { |
959 DeleteShortcutInApplicationsMenu(*it, | 973 DeleteShortcutInApplicationsMenu(*it, |
960 base::FilePath(kDirectoryFilename)); | 974 base::FilePath(kDirectoryFilename)); |
961 } | 975 } |
962 } | 976 } |
963 } | 977 } |
964 | 978 |
965 } // namespace ShellIntegrationLinux | 979 } // namespace ShellIntegrationLinux |
OLD | NEW |