Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(618)

Unified Diff: chrome/browser/shell_integration_linux.cc

Issue 12321107: Move shell integration code from chrome/browser to apps (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/shell_integration_linux.cc
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
deleted file mode 100644
index a97a072ae5622c6e678598059eca651c0bcf4c5a..0000000000000000000000000000000000000000
--- a/chrome/browser/shell_integration_linux.cc
+++ /dev/null
@@ -1,733 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/shell_integration_linux.h"
-
-#include <fcntl.h>
-#include <glib.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include "base/base_paths.h"
-#include "base/command_line.h"
-#include "base/environment.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/i18n/file_util_icu.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/process_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/common/chrome_constants.h"
-#include "content/public/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_rep.h"
-
-using content::BrowserThread;
-
-namespace {
-
-// Helper to launch xdg scripts. We don't want them to ask any questions on the
-// terminal etc. The function returns true if the utility launches and exits
-// cleanly, in which case |exit_code| returns the utility's exit code.
-bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) {
- // xdg-settings internally runs xdg-mime, which uses mv to move newly-created
- // files on top of originals after making changes to them. In the event that
- // the original files are owned by another user (e.g. root, which can happen
- // if they are updated within sudo), mv will prompt the user to confirm if
- // standard input is a terminal (otherwise it just does it). So make sure it's
- // not, to avoid locking everything up waiting for mv.
- *exit_code = EXIT_FAILURE;
- int devnull = open("/dev/null", O_RDONLY);
- if (devnull < 0)
- return false;
- base::FileHandleMappingVector no_stdin;
- no_stdin.push_back(std::make_pair(devnull, STDIN_FILENO));
-
- base::ProcessHandle handle;
- base::LaunchOptions options;
- options.fds_to_remap = &no_stdin;
- if (!base::LaunchProcess(argv, options, &handle)) {
- close(devnull);
- return false;
- }
- close(devnull);
-
- return base::WaitForExitCode(handle, exit_code);
-}
-
-std::string CreateShortcutIcon(
- const ShellIntegration::ShortcutInfo& shortcut_info,
- const base::FilePath& shortcut_filename) {
- if (shortcut_info.favicon.IsEmpty())
- return std::string();
-
- // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
- base::ScopedTempDir temp_dir;
- if (!temp_dir.CreateUniqueTempDir())
- return std::string();
-
- base::FilePath temp_file_path = temp_dir.path().Append(
- shortcut_filename.ReplaceExtension("png"));
- std::string icon_name = temp_file_path.BaseName().RemoveExtension().value();
-
- std::vector<gfx::ImageSkiaRep> image_reps =
- shortcut_info.favicon.ToImageSkia()->image_reps();
- for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin();
- it != image_reps.end(); ++it) {
- std::vector<unsigned char> png_data;
- const SkBitmap& bitmap = it->sk_bitmap();
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_data)) {
- // If the bitmap could not be encoded to PNG format, skip it.
- LOG(WARNING) << "Could not encode icon " << icon_name << ".png at size "
- << bitmap.width() << ".";
- continue;
- }
- int bytes_written = file_util::WriteFile(temp_file_path,
- reinterpret_cast<char*>(png_data.data()), png_data.size());
-
- if (bytes_written != static_cast<int>(png_data.size()))
- return std::string();
-
- std::vector<std::string> argv;
- argv.push_back("xdg-icon-resource");
- argv.push_back("install");
-
- // Always install in user mode, even if someone runs the browser as root
- // (people do that).
- argv.push_back("--mode");
- argv.push_back("user");
-
- argv.push_back("--size");
- argv.push_back(base::IntToString(bitmap.width()));
-
- argv.push_back(temp_file_path.value());
- argv.push_back(icon_name);
- int exit_code;
- if (!LaunchXdgUtility(argv, &exit_code) || exit_code) {
- LOG(WARNING) << "Could not install icon " << icon_name << ".png at size "
- << bitmap.width() << ".";
- }
- }
- return icon_name;
-}
-
-bool CreateShortcutOnDesktop(const base::FilePath& shortcut_filename,
- const std::string& contents) {
- // Make sure that we will later call openat in a secure way.
- DCHECK_EQ(shortcut_filename.BaseName().value(), shortcut_filename.value());
-
- base::FilePath desktop_path;
- if (!PathService::Get(base::DIR_USER_DESKTOP, &desktop_path))
- return false;
-
- int desktop_fd = open(desktop_path.value().c_str(), O_RDONLY | O_DIRECTORY);
- if (desktop_fd < 0)
- return false;
-
- int fd = openat(desktop_fd, shortcut_filename.value().c_str(),
- O_CREAT | O_EXCL | O_WRONLY,
- S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
- if (fd < 0) {
- if (HANDLE_EINTR(close(desktop_fd)) < 0)
- PLOG(ERROR) << "close";
- return false;
- }
-
- ssize_t bytes_written = file_util::WriteFileDescriptor(fd, contents.data(),
- contents.length());
- if (HANDLE_EINTR(close(fd)) < 0)
- PLOG(ERROR) << "close";
-
- if (bytes_written != static_cast<ssize_t>(contents.length())) {
- // Delete the file. No shortuct is better than corrupted one. Use unlinkat
- // to make sure we're deleting the file in the directory we think we are.
- // Even if an attacker manager to put something other at
- // |shortcut_filename| we'll just undo his action.
- unlinkat(desktop_fd, shortcut_filename.value().c_str(), 0);
- }
-
- if (HANDLE_EINTR(close(desktop_fd)) < 0)
- PLOG(ERROR) << "close";
-
- return true;
-}
-
-void DeleteShortcutOnDesktop(const base::FilePath& shortcut_filename) {
- base::FilePath desktop_path;
- if (PathService::Get(base::DIR_USER_DESKTOP, &desktop_path))
- file_util::Delete(desktop_path.Append(shortcut_filename), false);
-}
-
-bool CreateShortcutInApplicationsMenu(const base::FilePath& shortcut_filename,
- const std::string& contents) {
- base::ScopedTempDir temp_dir;
- if (!temp_dir.CreateUniqueTempDir())
- return false;
-
- base::FilePath temp_file_path = temp_dir.path().Append(shortcut_filename);
-
- int bytes_written = file_util::WriteFile(temp_file_path, contents.data(),
- contents.length());
-
- if (bytes_written != static_cast<int>(contents.length()))
- return false;
-
- std::vector<std::string> argv;
- argv.push_back("xdg-desktop-menu");
- argv.push_back("install");
-
- // Always install in user mode, even if someone runs the browser as root
- // (people do that).
- argv.push_back("--mode");
- argv.push_back("user");
-
- argv.push_back(temp_file_path.value());
- int exit_code;
- LaunchXdgUtility(argv, &exit_code);
- return exit_code == 0;
-}
-
-void DeleteShortcutInApplicationsMenu(const base::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) {
- // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
-
- // Quoting is only necessary if the argument has a reserved character.
- if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos)
- return arg; // No quoting necessary.
-
- std::string quoted = "\"";
- for (size_t i = 0; i < arg.size(); ++i) {
- // Note that the set of backslashed characters is smaller than the
- // set of reserved characters.
- switch (arg[i]) {
- case '"':
- case '`':
- case '$':
- case '\\':
- quoted += '\\';
- break;
- }
- quoted += arg[i];
- }
- quoted += '"';
-
- return quoted;
-}
-
-// Remove keys from the [Desktop Entry] that would be wrong if copied verbatim
-// into the new .desktop file.
-const char* kDesktopKeysToDelete[] = {
- "GenericName",
- "Comment",
- "MimeType",
- "X-Ayatana-Desktop-Shortcuts",
- "StartupWMClass",
- NULL
-};
-
-const char kDesktopEntry[] = "Desktop Entry";
-
-const char kXdgOpenShebang[] = "#!/usr/bin/env xdg-open";
-
-const char kXdgSettings[] = "xdg-settings";
-const char kXdgSettingsDefaultBrowser[] = "default-web-browser";
-const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler";
-
-// Regex to match a localized key name such as "Name[en_AU]".
-const char kLocalizedKeyRegex[] = "^[A-Za-z0-9\\-]+\\[[^\\]]*\\]$";
-
-} // namespace
-
-namespace {
-
-// Utility function to get the path to the version of a script shipped with
-// Chrome. |script| gives the name of the script. |chrome_version| returns the
-// path to the Chrome version of the script, and the return value of the
-// function is true if the function is successful and the Chrome version is
-// not the script found on the PATH.
-bool GetChromeVersionOfScript(const std::string& script,
- std::string* chrome_version) {
- // Get the path to the Chrome version.
- base::FilePath chrome_dir;
- if (!PathService::Get(base::DIR_EXE, &chrome_dir))
- return false;
-
- base::FilePath chrome_version_path = chrome_dir.Append(script);
- *chrome_version = chrome_version_path.value();
-
- // Check if this is different to the one on path.
- std::vector<std::string> argv;
- argv.push_back("which");
- argv.push_back(script);
- std::string path_version;
- if (base::GetAppOutput(CommandLine(argv), &path_version)) {
- // Remove trailing newline
- path_version.erase(path_version.length() - 1, 1);
- base::FilePath path_version_path(path_version);
- return (chrome_version_path != path_version_path);
- }
- return false;
-}
-
-// Value returned by xdg-settings if it can't understand our request.
-const int EXIT_XDG_SETTINGS_SYNTAX_ERROR = 1;
-
-// We delegate the difficulty of setting the default browser and default url
-// scheme handler in Linux desktop environments to an xdg utility, xdg-settings.
-
-// When calling this script we first try to use the script on PATH. If that
-// fails we then try to use the script that we have included. This gives
-// scripts on the system priority over ours, as distribution vendors may have
-// tweaked the script, but still allows our copy to be used if the script on the
-// system fails, as the system copy may be missing capabilities of the Chrome
-// copy.
-
-// If |protocol| is empty this function sets Chrome as the default browser,
-// otherwise it sets Chrome as the default handler application for |protocol|.
-bool SetDefaultWebClient(const std::string& protocol) {
-#if defined(OS_CHROMEOS)
- return true;
-#else
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- scoped_ptr<base::Environment> env(base::Environment::Create());
-
- std::vector<std::string> argv;
- argv.push_back(kXdgSettings);
- argv.push_back("set");
- if (protocol.empty()) {
- argv.push_back(kXdgSettingsDefaultBrowser);
- } else {
- argv.push_back(kXdgSettingsDefaultSchemeHandler);
- argv.push_back(protocol);
- }
- argv.push_back(ShellIntegrationLinux::GetDesktopName(env.get()));
-
- int exit_code;
- bool ran_ok = LaunchXdgUtility(argv, &exit_code);
- if (ran_ok && exit_code == EXIT_XDG_SETTINGS_SYNTAX_ERROR) {
- if (GetChromeVersionOfScript(kXdgSettings, &argv[0])) {
- ran_ok = LaunchXdgUtility(argv, &exit_code);
- }
- }
-
- return ran_ok && exit_code == EXIT_SUCCESS;
-#endif
-}
-
-// If |protocol| is empty this function checks if Chrome is the default browser,
-// otherwise it checks if Chrome is the default handler application for
-// |protocol|.
-ShellIntegration::DefaultWebClientState GetIsDefaultWebClient(
- const std::string& protocol) {
-#if defined(OS_CHROMEOS)
- return ShellIntegration::IS_DEFAULT;
-#else
- base::ThreadRestrictions::AssertIOAllowed();
-
- scoped_ptr<base::Environment> env(base::Environment::Create());
-
- std::vector<std::string> argv;
- argv.push_back(kXdgSettings);
- argv.push_back("check");
- if (protocol.empty()) {
- argv.push_back(kXdgSettingsDefaultBrowser);
- } else {
- argv.push_back(kXdgSettingsDefaultSchemeHandler);
- argv.push_back(protocol);
- }
- argv.push_back(ShellIntegrationLinux::GetDesktopName(env.get()));
-
- std::string reply;
- int success_code;
- bool ran_ok = base::GetAppOutputWithExitCode(CommandLine(argv), &reply,
- &success_code);
- if (ran_ok && success_code == EXIT_XDG_SETTINGS_SYNTAX_ERROR) {
- if (GetChromeVersionOfScript(kXdgSettings, &argv[0])) {
- ran_ok = base::GetAppOutputWithExitCode(CommandLine(argv), &reply,
- &success_code);
- }
- }
-
- if (!ran_ok || success_code != EXIT_SUCCESS) {
- // xdg-settings failed: we can't determine or set the default browser.
- return ShellIntegration::UNKNOWN_DEFAULT;
- }
-
- // Allow any reply that starts with "yes".
- return (reply.find("yes") == 0) ? ShellIntegration::IS_DEFAULT :
- ShellIntegration::NOT_DEFAULT;
-#endif
-}
-
-} // namespace
-
-// static
-ShellIntegration::DefaultWebClientSetPermission
- ShellIntegration::CanSetAsDefaultBrowser() {
- return SET_DEFAULT_UNATTENDED;
-}
-
-// static
-bool ShellIntegration::SetAsDefaultBrowser() {
- return SetDefaultWebClient("");
-}
-
-// static
-bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) {
- return SetDefaultWebClient(protocol);
-}
-
-// static
-ShellIntegration::DefaultWebClientState ShellIntegration::GetDefaultBrowser() {
- return GetIsDefaultWebClient("");
-}
-
-// static
-std::string ShellIntegration::GetApplicationForProtocol(const GURL& url) {
- return std::string("xdg-open");
-}
-
-// static
-ShellIntegration::DefaultWebClientState
-ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) {
- return GetIsDefaultWebClient(protocol);
-}
-
-// static
-bool ShellIntegration::IsFirefoxDefaultBrowser() {
- std::vector<std::string> argv;
- argv.push_back(kXdgSettings);
- argv.push_back("get");
- argv.push_back(kXdgSettingsDefaultBrowser);
-
- std::string browser;
- // We don't care about the return value here.
- base::GetAppOutput(CommandLine(argv), &browser);
- return browser.find("irefox") != std::string::npos;
-}
-
-namespace ShellIntegrationLinux {
-
-std::string GetDesktopName(base::Environment* env) {
-#if defined(GOOGLE_CHROME_BUILD)
- return "google-chrome.desktop";
-#else // CHROMIUM_BUILD
- // Allow $CHROME_DESKTOP to override the built-in value, so that development
- // versions can set themselves as the default without interfering with
- // non-official, packaged versions using the built-in value.
- std::string name;
- if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
- return name;
- return "chromium-browser.desktop";
-#endif
-}
-
-bool GetDesktopShortcutTemplate(base::Environment* env,
- std::string* output) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- std::vector<base::FilePath> search_paths;
-
- std::string xdg_data_home;
- if (env->GetVar("XDG_DATA_HOME", &xdg_data_home) &&
- !xdg_data_home.empty()) {
- search_paths.push_back(base::FilePath(xdg_data_home));
- }
-
- std::string xdg_data_dirs;
- if (env->GetVar("XDG_DATA_DIRS", &xdg_data_dirs) &&
- !xdg_data_dirs.empty()) {
- base::StringTokenizer tokenizer(xdg_data_dirs, ":");
- while (tokenizer.GetNext()) {
- base::FilePath data_dir(tokenizer.token());
- search_paths.push_back(data_dir);
- search_paths.push_back(data_dir.Append("applications"));
- }
- }
-
- // Add some fallback paths for systems which don't have XDG_DATA_DIRS or have
- // it incomplete.
- search_paths.push_back(base::FilePath("/usr/share/applications"));
- search_paths.push_back(base::FilePath("/usr/local/share/applications"));
-
- std::string template_filename(GetDesktopName(env));
- for (std::vector<base::FilePath>::const_iterator i = search_paths.begin();
- i != search_paths.end(); ++i) {
- base::FilePath path = i->Append(template_filename);
- VLOG(1) << "Looking for desktop file template in " << path.value();
- if (file_util::PathExists(path)) {
- VLOG(1) << "Found desktop file template at " << path.value();
- return file_util::ReadFileToString(path, output);
- }
- }
-
- LOG(ERROR) << "Could not find desktop file template.";
- return false;
-}
-
-base::FilePath GetWebShortcutFilename(const GURL& url) {
- // Use a prefix, because xdg-desktop-menu requires it.
- std::string filename =
- std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec();
- file_util::ReplaceIllegalCharactersInPath(&filename, '_');
-
- base::FilePath desktop_path;
- if (!PathService::Get(base::DIR_USER_DESKTOP, &desktop_path))
- return base::FilePath();
-
- base::FilePath filepath = desktop_path.Append(filename);
- base::FilePath alternative_filepath(filepath.value() + ".desktop");
- for (size_t i = 1; i < 100; ++i) {
- if (file_util::PathExists(base::FilePath(alternative_filepath))) {
- alternative_filepath = base::FilePath(
- filepath.value() + "_" + base::IntToString(i) + ".desktop");
- } else {
- return base::FilePath(alternative_filepath).BaseName();
- }
- }
-
- return base::FilePath();
-}
-
-base::FilePath GetExtensionShortcutFilename(const base::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 base::FilePath(filename.append(".desktop"));
-}
-
-std::string GetDesktopFileContents(
- const std::string& template_contents,
- const std::string& app_name,
- const GURL& url,
- const std::string& extension_id,
- const base::FilePath& extension_path,
- const string16& title,
- const std::string& icon_name,
- const base::FilePath& profile_path) {
- // Although not required by the spec, Nautilus on Ubuntu Karmic creates its
- // launchers with an xdg-open shebang. Follow that convention.
- std::string output_buffer = std::string(kXdgOpenShebang) + "\n";
- if (template_contents.empty())
- return output_buffer;
-
- // See http://standards.freedesktop.org/desktop-entry-spec/latest/
- // http://developer.gnome.org/glib/unstable/glib-Key-value-file-parser.html
- GKeyFile* key_file = g_key_file_new();
- GError* err = NULL;
- // Loading the data will strip translations and comments from the desktop
- // file (which we want to do!)
- if (!g_key_file_load_from_data(
- key_file,
- template_contents.c_str(),
- template_contents.size(),
- G_KEY_FILE_NONE,
- &err)) {
- NOTREACHED() << "Unable to read desktop file template:" << err->message;
- g_error_free(err);
- return output_buffer;
- }
-
- // Remove all sections except for the Desktop Entry
- gsize length = 0;
- gchar** groups = g_key_file_get_groups(key_file, &length);
- for (gsize i = 0; i < length; ++i) {
- if (strcmp(groups[i], kDesktopEntry) != 0) {
- g_key_file_remove_group(key_file, groups[i], NULL);
- }
- }
- g_strfreev(groups);
-
- // Remove keys that we won't need.
- for (const char** current_key = kDesktopKeysToDelete; *current_key;
- ++current_key) {
- g_key_file_remove_key(key_file, kDesktopEntry, *current_key, NULL);
- }
- // Remove all localized keys.
- GRegex* localized_key_regex = g_regex_new(kLocalizedKeyRegex,
- static_cast<GRegexCompileFlags>(0),
- static_cast<GRegexMatchFlags>(0),
- NULL);
- gchar** keys = g_key_file_get_keys(key_file, kDesktopEntry, NULL, NULL);
- for (gchar** keys_ptr = keys; *keys_ptr; ++keys_ptr) {
- if (g_regex_match(localized_key_regex, *keys_ptr,
- static_cast<GRegexMatchFlags>(0), NULL)) {
- g_key_file_remove_key(key_file, kDesktopEntry, *keys_ptr, NULL);
- }
- }
- g_strfreev(keys);
- g_regex_unref(localized_key_regex);
-
- // Set the "Name" key.
- std::string final_title = UTF16ToUTF8(title);
- // Make sure no endline characters can slip in and possibly introduce
- // additional lines (like Exec, which makes it a security risk). Also
- // use the URL as a default when the title is empty.
- if (final_title.empty() ||
- final_title.find("\n") != std::string::npos ||
- final_title.find("\r") != std::string::npos) {
- final_title = url.spec();
- }
- g_key_file_set_string(key_file, kDesktopEntry, "Name", final_title.c_str());
-
- // Set the "Exec" key.
- char* exec_c_string = g_key_file_get_string(key_file, kDesktopEntry, "Exec",
- NULL);
- if (exec_c_string) {
- std::string exec_string(exec_c_string);
- g_free(exec_c_string);
- base::StringTokenizer exec_tokenizer(exec_string, " ");
-
- std::string final_path;
- while (exec_tokenizer.GetNext() && exec_tokenizer.token() != "%U") {
- if (!final_path.empty())
- final_path += " ";
- final_path += exec_tokenizer.token();
- }
- CommandLine cmd_line(CommandLine::NO_PROGRAM);
- cmd_line = ShellIntegration::CommandLineArgsForLauncher(
- url, extension_id, profile_path);
- const CommandLine::SwitchMap& switch_map = cmd_line.GetSwitches();
- for (CommandLine::SwitchMap::const_iterator i = switch_map.begin();
- i != switch_map.end(); ++i) {
- if (i->second.empty()) {
- final_path += " --" + i->first;
- } else {
- final_path += " " + QuoteArgForDesktopFileExec("--" + i->first +
- "=" + i->second);
- }
- }
-
- g_key_file_set_string(key_file, kDesktopEntry, "Exec", final_path.c_str());
- }
-
- // Set the "Icon" key.
- if (!icon_name.empty())
- g_key_file_set_string(key_file, kDesktopEntry, "Icon", icon_name.c_str());
-
-#if defined(TOOLKIT_GTK)
- std::string wmclass = web_app::GetWMClassFromAppName(app_name);
- g_key_file_set_string(key_file, kDesktopEntry, "StartupWMClass",
- wmclass.c_str());
-#endif
-
- length = 0;
- gchar* data_dump = g_key_file_to_data(key_file, &length, NULL);
- if (data_dump) {
- // If strlen(data_dump[0]) == 0, this check will fail.
- if (data_dump[0] == '\n') {
- // Older versions of glib produce a leading newline. If this is the case,
- // remove it to avoid double-newline after the shebang.
- output_buffer += (data_dump + 1);
- } else {
- output_buffer += data_dump;
- }
- g_free(data_dump);
- }
-
- g_key_file_free(key_file);
- return output_buffer;
-}
-
-bool CreateDesktopShortcut(
- const ShellIntegration::ShortcutInfo& shortcut_info,
- const std::string& shortcut_template) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- base::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;
-
- std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename);
-
- std::string app_name =
- web_app::GenerateApplicationNameFromInfo(shortcut_info);
- std::string contents = ShellIntegrationLinux::GetDesktopFileContents(
- shortcut_template,
- app_name,
- shortcut_info.url,
- shortcut_info.extension_id,
- shortcut_info.extension_path,
- shortcut_info.title,
- icon_name,
- shortcut_info.profile_path);
-
- bool success = true;
-
- if (shortcut_info.create_on_desktop)
- success = CreateShortcutOnDesktop(shortcut_filename, contents);
-
- if (shortcut_info.create_in_applications_menu)
- success = CreateShortcutInApplicationsMenu(shortcut_filename, contents) &&
- success;
-
- return success;
-}
-
-void DeleteDesktopShortcuts(const base::FilePath& profile_path,
- const std::string& extension_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- base::FilePath shortcut_filename = GetExtensionShortcutFilename(
- profile_path, extension_id);
- DCHECK(!shortcut_filename.empty());
-
- DeleteShortcutOnDesktop(shortcut_filename);
- DeleteShortcutInApplicationsMenu(shortcut_filename);
-}
-
-} // namespace ShellIntegrationLinux

Powered by Google App Engine
This is Rietveld 408576698