summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-11 06:10:07 +0000
committerbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-11 06:10:07 +0000
commit914636612ba4bf032b809e1dcf09a11f87384515 (patch)
tree93fbe4da0ae3e9ac17064e64430a707621722450
parentc15faf37bc7ae6421489be2f69403e95df9ca237 (diff)
downloadchromium_src-914636612ba4bf032b809e1dcf09a11f87384515.zip
chromium_src-914636612ba4bf032b809e1dcf09a11f87384515.tar.gz
chromium_src-914636612ba4bf032b809e1dcf09a11f87384515.tar.bz2
Remove app shortcuts when app is uninstalled on Linux.
To support this, shortcut creation on Linux for extensions has been modified so that the filename encodes the extension ID and the profile. Also, when creating shortcuts any existing shortcuts are removed first. Web page shortcuts are not affected. BUG=130456 TEST=Test uninstalling apps removes their shortcuts; test uninstalling apps is not broken in any way; test shortcuts for web apps are not broken in any way. Review URL: https://chromiumcodereview.appspot.com/10698114 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146065 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/app_shortcut_manager.cc33
-rw-r--r--chrome/browser/shell_integration_linux.cc65
-rw-r--r--chrome/browser/shell_integration_linux.h18
-rw-r--r--chrome/browser/shell_integration_unittest.cc4
-rw-r--r--chrome/browser/web_applications/web_app.cc14
-rw-r--r--chrome/browser/web_applications/web_app.h11
-rw-r--r--chrome/browser/web_applications/web_app_linux.cc5
-rw-r--r--chrome/browser/web_applications/web_app_win.cc5
8 files changed, 138 insertions, 17 deletions
diff --git a/chrome/browser/extensions/app_shortcut_manager.cc b/chrome/browser/extensions/app_shortcut_manager.cc
index 53aba19..a3357f8 100644
--- a/chrome/browser/extensions/app_shortcut_manager.cc
+++ b/chrome/browser/extensions/app_shortcut_manager.cc
@@ -36,6 +36,8 @@ AppShortcutManager::AppShortcutManager(Profile* profile)
tracker_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
content::Source<Profile>(profile_));
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
+ content::Source<Profile>(profile_));
}
void AppShortcutManager::OnImageLoaded(const gfx::Image& image,
@@ -61,15 +63,28 @@ void AppShortcutManager::OnImageLoaded(const gfx::Image& image,
void AppShortcutManager::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
- DCHECK(type == chrome::NOTIFICATION_EXTENSION_INSTALLED);
- #if !defined(OS_MACOSX)
- const Extension* extension = content::Details<const Extension>(
- details).ptr();
- if (!disable_shortcut_creation_for_tests &&
- extension->is_platform_app() &&
- extension->location() != Extension::LOAD)
- InstallApplicationShortcuts(extension);
- #endif
+#if !defined(OS_MACOSX)
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
+ const Extension* extension = content::Details<const Extension>(
+ details).ptr();
+ if (!disable_shortcut_creation_for_tests &&
+ extension->is_platform_app() &&
+ extension->location() != Extension::LOAD) {
+ InstallApplicationShortcuts(extension);
+ }
+ break;
+ }
+ case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
+ std::string extension_id = *content::Details<std::string>(details).ptr();
+ if (!disable_shortcut_creation_for_tests)
+ web_app::DeleteAllShortcuts(profile_->GetPath(), extension_id);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+#endif
}
// static
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 840f056..ea05095 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -154,6 +154,12 @@ bool CreateShortcutOnDesktop(const FilePath& shortcut_filename,
return true;
}
+void DeleteShortcutOnDesktop(const FilePath& shortcut_filename) {
+ FilePath desktop_path;
+ if (PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
+ file_util::Delete(desktop_path.Append(shortcut_filename), false);
+}
+
bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename,
const std::string& contents) {
ScopedTempDir temp_dir;
@@ -183,6 +189,22 @@ bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename,
return exit_code == 0;
}
+void DeleteShortcutInApplicationsMenu(const FilePath& shortcut_filename) {
+ std::vector<std::string> argv;
+ argv.push_back("xdg-desktop-menu");
+ argv.push_back("uninstall");
+
+ // Uninstall in user mode, to match the install.
+ argv.push_back("--mode");
+ argv.push_back("user");
+
+ // The file does not need to exist anywhere - xdg-desktop-menu will uninstall
+ // items from the menu with a matching name.
+ argv.push_back(shortcut_filename.value());
+ int exit_code;
+ LaunchXdgUtility(argv, &exit_code);
+}
+
// Quote a string such that it appears as one verbatim argument for the Exec
// key in a desktop file.
std::string QuoteArgForDesktopFileExec(const std::string& arg) {
@@ -455,7 +477,7 @@ bool GetDesktopShortcutTemplate(base::Environment* env,
return false;
}
-FilePath GetDesktopShortcutFilename(const GURL& url) {
+FilePath GetWebShortcutFilename(const GURL& url) {
// Use a prefix, because xdg-desktop-menu requires it.
std::string filename =
std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec();
@@ -479,6 +501,20 @@ FilePath GetDesktopShortcutFilename(const GURL& url) {
return FilePath();
}
+FilePath GetExtensionShortcutFilename(const FilePath& profile_path,
+ const std::string& extension_id) {
+ DCHECK(!extension_id.empty());
+
+ // Use a prefix, because xdg-desktop-menu requires it.
+ std::string filename(chrome::kBrowserProcessExecutableName);
+ filename.append("-")
+ .append(extension_id)
+ .append("-")
+ .append(profile_path.BaseName().value());
+ file_util::ReplaceIllegalCharactersInPath(&filename, '_');
+ return FilePath(filename.append(".desktop"));
+}
+
std::string GetDesktopFileContents(
const std::string& template_contents,
const std::string& app_name,
@@ -597,8 +633,19 @@ bool CreateDesktopShortcut(
const std::string& shortcut_template) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- FilePath shortcut_filename =
- ShellIntegrationLinux::GetDesktopShortcutFilename(shortcut_info.url);
+ FilePath shortcut_filename;
+ if (!shortcut_info.extension_id.empty()) {
+ shortcut_filename = GetExtensionShortcutFilename(
+ shortcut_info.profile_path, shortcut_info.extension_id);
+ // For extensions we do not want duplicate shortcuts. So, delete any that
+ // already exist and replace them.
+ if (shortcut_info.create_on_desktop)
+ DeleteShortcutOnDesktop(shortcut_filename);
+ if (shortcut_info.create_in_applications_menu)
+ DeleteShortcutInApplicationsMenu(shortcut_filename);
+ } else {
+ shortcut_filename = GetWebShortcutFilename(shortcut_info.url);
+ }
if (shortcut_filename.empty())
return false;
@@ -629,4 +676,16 @@ bool CreateDesktopShortcut(
return success;
}
+void DeleteDesktopShortcuts(const FilePath& profile_path,
+ const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ FilePath shortcut_filename = GetExtensionShortcutFilename(
+ profile_path, extension_id);
+ DCHECK(!shortcut_filename.empty());
+
+ DeleteShortcutOnDesktop(shortcut_filename);
+ DeleteShortcutInApplicationsMenu(shortcut_filename);
+}
+
} // namespace ShellIntegrationLinux
diff --git a/chrome/browser/shell_integration_linux.h b/chrome/browser/shell_integration_linux.h
index 5886250..643068a 100644
--- a/chrome/browser/shell_integration_linux.h
+++ b/chrome/browser/shell_integration_linux.h
@@ -26,7 +26,12 @@ bool GetDesktopShortcutTemplate(base::Environment* env,
std::string* output);
// Returns filename for .desktop file based on |url|, sanitized for security.
-FilePath GetDesktopShortcutFilename(const GURL& url);
+FilePath GetWebShortcutFilename(const GURL& url);
+
+// Returns filename for .desktop file based on |profile_path| and
+// |extension_id|, sanitized for security.
+FilePath GetExtensionShortcutFilename(const FilePath& profile_path,
+ const std::string& extension_id);
// Returns contents for .desktop file based on |template_contents|, |url|
// and |title|. The |template_contents| should be contents of .desktop file
@@ -41,9 +46,20 @@ std::string GetDesktopFileContents(const std::string& template_contents,
const std::string& icon_name,
const FilePath& profile_path);
+
+// Create shortcuts on the desktop or in the application menu (as specified by
+// |shortcut_info|), for the web page or extension in |shortcut_info|. Use the
+// shortcut template contained in |shortcut_template|.
+// For extensions, duplicate shortcuts are avoided, so if a requested shortcut
+// already exists it is deleted first.
bool CreateDesktopShortcut(const ShellIntegration::ShortcutInfo& shortcut_info,
const std::string& shortcut_template);
+// Delete any desktop shortcuts on desktop or in the application menu that have
+// been added for the extension with |extension_id| in |profile_path|.
+void DeleteDesktopShortcuts(const FilePath& profile_path,
+ const std::string& extension_id);
+
} // namespace ShellIntegrationLinux
#endif // CHROME_BROWSER_SHELL_INTEGRATION_LINUX_H_
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index 63921e7..31ea4a3 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -139,7 +139,7 @@ TEST(ShellIntegrationTest, GetDesktopShortcutTemplate) {
}
}
-TEST(ShellIntegrationTest, GetDesktopShortcutFilename) {
+TEST(ShellIntegrationTest, GetWebShortcutFilename) {
const struct {
const FilePath::CharType* path;
const char* url;
@@ -156,7 +156,7 @@ TEST(ShellIntegrationTest, GetDesktopShortcutFilename) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
EXPECT_EQ(std::string(chrome::kBrowserProcessExecutableName) + "-" +
test_cases[i].path,
- ShellIntegrationLinux::GetDesktopShortcutFilename(
+ ShellIntegrationLinux::GetWebShortcutFilename(
GURL(test_cases[i].url)).value()) <<
" while testing " << test_cases[i].url;
}
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index a502b5a..c2b2a34 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -127,8 +127,18 @@ void CreateShortcut(
BrowserThread::FILE,
FROM_HERE,
base::Bind(base::IgnoreResult(&CreateShortcutOnFileThread),
- profile_path,
- shortcut_info));
+ profile_path, shortcut_info));
+}
+
+void DeleteAllShortcuts(const FilePath& profile_path,
+ const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&internals::DeletePlatformShortcuts, profile_path,
+ extension_id));
}
bool CreateShortcutOnFileThread(
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index 253c88f..bcd445a 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -54,6 +54,11 @@ void CreateShortcut(
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info);
+// Delete all the shortcuts that have been created for the extension with
+// |extension_id| in the profile with |profile_path|.
+void DeleteAllShortcuts(const FilePath& profile_path,
+ const std::string& extension_id);
+
// Creates a shortcut. Must be called on the file thread. This is used to
// implement CreateShortcut() above, and can also be used directly from the
// file thread. |profile_path| is the path of the creating profile.
@@ -97,6 +102,12 @@ bool CreatePlatformShortcut(
const FilePath& profile_path,
const ShellIntegration::ShortcutInfo& shortcut_info);
+// Delete all the shortcuts we have added for this extension. This is the
+// platform specific implementation of the DeleteAllShortcuts function, and
+// is executed on the FILE thread..
+void DeletePlatformShortcuts(const FilePath& profile_path,
+ const std::string& extension_id);
+
// Sanitizes |name| and returns a version of it that is safe to use as an
// on-disk file name .
FilePath GetSanitizedFileName(const string16& name);
diff --git a/chrome/browser/web_applications/web_app_linux.cc b/chrome/browser/web_applications/web_app_linux.cc
index e26be43..56d02fbf 100644
--- a/chrome/browser/web_applications/web_app_linux.cc
+++ b/chrome/browser/web_applications/web_app_linux.cc
@@ -29,5 +29,10 @@ bool CreatePlatformShortcut(
shortcut_info, shortcut_template);
}
+void DeletePlatformShortcuts(const FilePath& profile_path,
+ const std::string& extension_id) {
+ ShellIntegrationLinux::DeleteDesktopShortcuts(profile_path, extension_id);
+}
+
} // namespace internals
} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc
index f6cbbbf1..f5d85bd 100644
--- a/chrome/browser/web_applications/web_app_win.cc
+++ b/chrome/browser/web_applications/web_app_win.cc
@@ -255,6 +255,11 @@ bool CreatePlatformShortcut(
return success;
}
+void DeletePlatformShortcuts(const FilePath& profile_path,
+ const std::string& extension_id) {
+ // TODO(benwells): Implement this.
+}
+
} // namespace internals
} // namespace web_app