| 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 |