Chromium Code Reviews| 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 |