summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc16
-rw-r--r--chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h1
-rw-r--r--chrome/browser/shell_integration.h18
-rw-r--r--chrome/browser/shell_integration_linux.cc124
-rw-r--r--chrome/browser/shell_integration_unittest.cc9
6 files changed, 116 insertions, 55 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index f7b250b..96bfc63 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1808,6 +1808,9 @@ each locale. -->
<message name="IDS_CREATE_SHORTCUTS_DESKTOP_CHKBOX" desc="Label of the checkbox to create an application shortcut on the desktop.">
Desktop
</message>
+ <message name="IDS_CREATE_SHORTCUTS_MENU_CHKBOX" desc="Label of the checkbox to create an application shortcut in the system's applications menu.">
+ Applications menu
+ </message>
<message name="IDS_CREATE_SHORTCUTS_COMMIT" desc="Title of the button to actually create the shortcuts.">
Create
</message>
diff --git a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
index 6997651..91052e2 100644
--- a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
+++ b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
@@ -50,6 +50,12 @@ CreateApplicationShortcutsDialogGtk::CreateApplicationShortcutsDialogGtk(
gtk_box_pack_start(GTK_BOX(vbox), desktop_checkbox_, FALSE, FALSE, 0);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(desktop_checkbox_), true);
+ // Menu checkbox.
+ menu_checkbox_ = gtk_check_button_new_with_label(
+ l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_MENU_CHKBOX).c_str());
+ gtk_box_pack_start(GTK_BOX(vbox), menu_checkbox_, FALSE, FALSE, 0);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(menu_checkbox_), false);
+
g_signal_connect(dialog, "response",
G_CALLBACK(HandleOnResponseDialog), this);
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
@@ -59,8 +65,14 @@ CreateApplicationShortcutsDialogGtk::CreateApplicationShortcutsDialogGtk(
void CreateApplicationShortcutsDialogGtk::OnDialogResponse(GtkWidget* widget,
int response) {
if (response == GTK_RESPONSE_ACCEPT) {
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(desktop_checkbox_)))
- ShellIntegration::CreateDesktopShortcut(url_, title_);
+ ShellIntegration::ShortcutInfo shortcut_info;
+ shortcut_info.url = url_;
+ shortcut_info.title = title_;
+ shortcut_info.create_on_desktop =
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(desktop_checkbox_));
+ shortcut_info.create_in_applications_menu =
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(menu_checkbox_));
+ ShellIntegration::CreateDesktopShortcut(shortcut_info);
}
delete this;
diff --git a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h
index 79b54306..f1b9081 100644
--- a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h
+++ b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.h
@@ -33,6 +33,7 @@ class CreateApplicationShortcutsDialogGtk {
// UI elements.
GtkWidget* desktop_checkbox_;
+ GtkWidget* menu_checkbox_;
// Target URL of the shortcut.
GURL url_;
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index 9abfadd..2bc955c 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -10,9 +10,9 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/string16.h"
+#include "googleurl/src/gurl.h"
class FilePath;
-class GURL;
class MessageLoop;
class ShellIntegration {
@@ -42,10 +42,18 @@ class ShellIntegration {
const std::string& template_contents, const GURL& url,
const string16& title);
- // Creates a desktop shortcut for |url| with |title|. It is not guaranteed
- // to exist immediately after returning from this function, because actual
- // file operation is done on the file thread.
- static void CreateDesktopShortcut(const GURL& url, const string16& title);
+ struct ShortcutInfo {
+ GURL url;
+ string16 title;
+
+ bool create_on_desktop;
+ bool create_in_applications_menu;
+ };
+
+ // Creates a desktop shortcut. It is not guaranteed to exist immediately after
+ // returning from this function, because actual file operation is done on the
+ // file thread.
+ static void CreateDesktopShortcut(const ShortcutInfo& shortcut_info);
#endif // defined(OS_LINUX)
// The current default browser UI state
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index ea38c57..c7077d1 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -10,18 +10,22 @@
#include <sys/types.h>
#include <unistd.h>
+#include <string>
#include <vector>
+#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
+#include "base/scoped_temp_dir.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "googleurl/src/gurl.h"
@@ -45,6 +49,33 @@ const char* GetDesktopName() {
#endif
}
+// Helper to launch xdg scripts. We don't want them to ask any questions on the
+// terminal etc.
+bool LaunchXdgUtility(const std::vector<std::string>& argv) {
+ // 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.
+ int devnull = open("/dev/null", O_RDONLY);
+ if (devnull < 0)
+ return false;
+ base::file_handle_mapping_vector no_stdin;
+ no_stdin.push_back(std::make_pair(devnull, STDIN_FILENO));
+
+ base::ProcessHandle handle;
+ if (!base::LaunchApp(argv, no_stdin, false, &handle)) {
+ close(devnull);
+ return false;
+ }
+ close(devnull);
+
+ int success_code;
+ base::WaitForExitCode(handle, &success_code);
+ return success_code == EXIT_SUCCESS;
+}
+
bool GetDesktopShortcutTemplate(std::string* output) {
std::vector<std::string> search_paths;
@@ -74,38 +105,61 @@ bool GetDesktopShortcutTemplate(std::string* output) {
class CreateDesktopShortcutTask : public Task {
public:
- CreateDesktopShortcutTask(const GURL& url, const string16& title)
- : url_(url),
- title_(title) {
+ CreateDesktopShortcutTask(const ShellIntegration::ShortcutInfo& shortcut_info)
+ : shortcut_info_(shortcut_info) {
}
virtual void Run() {
// TODO(phajdan.jr): Report errors from this function, possibly as infobars.
- FilePath desktop_path;
- if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
- return;
- desktop_path =
- desktop_path.Append(ShellIntegration::GetDesktopShortcutFilename(url_));
-
- if (file_util::PathExists(desktop_path))
- return;
-
std::string template_contents;
if (!GetDesktopShortcutTemplate(&template_contents))
return;
std::string contents = ShellIntegration::GetDesktopFileContents(
- template_contents, url_, title_);
- int bytes_written = file_util::WriteFile(desktop_path, contents.data(),
+ template_contents, shortcut_info_.url, shortcut_info_.title);
+
+ ScopedTempDir temp_dir;
+ if (!temp_dir.CreateUniqueTempDir())
+ return;
+
+ FilePath shortcut_filename =
+ ShellIntegration::GetDesktopShortcutFilename(shortcut_info_.url);
+
+ 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())) {
- file_util::Delete(desktop_path, false);
+
+ if (bytes_written != static_cast<int>(contents.length()))
+ return;
+
+ if (shortcut_info_.create_on_desktop) {
+ FilePath desktop_path;
+ if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
+ return;
+ desktop_path = desktop_path.Append(shortcut_filename);
+
+ if (!file_util::PathExists(desktop_path))
+ file_util::CopyFile(temp_file_path, desktop_path);
+ }
+
+ if (shortcut_info_.create_in_applications_menu) {
+ 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());
+ LaunchXdgUtility(argv);
}
}
private:
- const GURL url_; // URL of the web application.
- const string16 title_; // Title displayed to the user.
+ const ShellIntegration::ShortcutInfo shortcut_info_;
DISALLOW_COPY_AND_ASSIGN(CreateDesktopShortcutTask);
};
@@ -123,29 +177,7 @@ bool ShellIntegration::SetAsDefaultBrowser() {
argv.push_back("set");
argv.push_back("default-web-browser");
argv.push_back(GetDesktopName());
-
- // 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.
- int devnull = open("/dev/null", O_RDONLY);
- if (devnull < 0)
- return false;
- base::file_handle_mapping_vector no_stdin;
- no_stdin.push_back(std::make_pair(devnull, STDIN_FILENO));
-
- base::ProcessHandle handle;
- if (!base::LaunchApp(argv, no_stdin, false, &handle)) {
- close(devnull);
- return false;
- }
- close(devnull);
-
- int success_code;
- base::WaitForExitCode(handle, &success_code);
- return success_code == EXIT_SUCCESS;
+ return LaunchXdgUtility(argv);
}
bool ShellIntegration::IsDefaultBrowser() {
@@ -181,7 +213,9 @@ bool ShellIntegration::IsFirefoxDefaultBrowser() {
}
FilePath ShellIntegration::GetDesktopShortcutFilename(const GURL& url) {
- std::wstring filename = UTF8ToWide(url.spec()) + L".desktop";
+ // Use a prefix, because xdg-desktop-menu requires it.
+ std::wstring filename = std::wstring(chrome::kBrowserProcessExecutableName) +
+ L"-" + UTF8ToWide(url.spec()) + L".desktop";
file_util::ReplaceIllegalCharacters(&filename, '_');
// Return BaseName to be absolutely sure we're not vulnerable to a directory
@@ -231,8 +265,8 @@ std::string ShellIntegration::GetDesktopFileContents(
return output_buffer;
}
-void ShellIntegration::CreateDesktopShortcut(const GURL& url,
- const string16& title) {
+void ShellIntegration::CreateDesktopShortcut(
+ const ShortcutInfo& shortcut_info) {
g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
- new CreateDesktopShortcutTask(url, title));
+ new CreateDesktopShortcutTask(shortcut_info));
}
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index fe01fc1..6f0d71d 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -6,6 +6,7 @@
#include "base/file_path.h"
#include "base/string_util.h"
+#include "chrome/common/chrome_constants.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,9 +28,11 @@ TEST(ShellIntegrationTest, GetDesktopShortcutFilename) {
{ FPL("http___.._.desktop"), "http://../../../../" },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
- EXPECT_EQ(test_cases[i].path, ShellIntegration::GetDesktopShortcutFilename(
- GURL(test_cases[i].url)).value()) << " while testing " <<
- test_cases[i].url;
+ EXPECT_EQ(WideToASCII(chrome::kBrowserProcessExecutableName) + "-" +
+ test_cases[i].path,
+ ShellIntegration::GetDesktopShortcutFilename(
+ GURL(test_cases[i].url)).value()) <<
+ " while testing " << test_cases[i].url;
}
}