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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 // |shortcut_filename| we'll just undo his action. | 147 // |shortcut_filename| we'll just undo his action. |
148 unlinkat(desktop_fd, shortcut_filename.value().c_str(), 0); | 148 unlinkat(desktop_fd, shortcut_filename.value().c_str(), 0); |
149 } | 149 } |
150 | 150 |
151 if (HANDLE_EINTR(close(desktop_fd)) < 0) | 151 if (HANDLE_EINTR(close(desktop_fd)) < 0) |
152 PLOG(ERROR) << "close"; | 152 PLOG(ERROR) << "close"; |
153 | 153 |
154 return true; | 154 return true; |
155 } | 155 } |
156 | 156 |
157 void DeleteShortcutOnDesktop(const FilePath& shortcut_filename) { | |
158 FilePath desktop_path; | |
159 if (PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) | |
160 file_util::Delete(desktop_path.Append(shortcut_filename), false); | |
161 } | |
162 | |
163 bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename, | 157 bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename, |
164 const std::string& contents) { | 158 const std::string& contents) { |
165 ScopedTempDir temp_dir; | 159 ScopedTempDir temp_dir; |
166 if (!temp_dir.CreateUniqueTempDir()) | 160 if (!temp_dir.CreateUniqueTempDir()) |
167 return false; | 161 return false; |
168 | 162 |
169 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); | 163 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); |
170 | 164 |
171 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), | 165 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), |
172 contents.length()); | 166 contents.length()); |
173 | 167 |
174 if (bytes_written != static_cast<int>(contents.length())) | 168 if (bytes_written != static_cast<int>(contents.length())) |
175 return false; | 169 return false; |
176 | 170 |
177 std::vector<std::string> argv; | 171 std::vector<std::string> argv; |
178 argv.push_back("xdg-desktop-menu"); | 172 argv.push_back("xdg-desktop-menu"); |
179 argv.push_back("install"); | 173 argv.push_back("install"); |
180 | 174 |
181 // Always install in user mode, even if someone runs the browser as root | 175 // Always install in user mode, even if someone runs the browser as root |
182 // (people do that). | 176 // (people do that). |
183 argv.push_back("--mode"); | 177 argv.push_back("--mode"); |
184 argv.push_back("user"); | 178 argv.push_back("user"); |
185 | 179 |
186 argv.push_back(temp_file_path.value()); | 180 argv.push_back(temp_file_path.value()); |
187 int exit_code; | 181 int exit_code; |
188 LaunchXdgUtility(argv, &exit_code); | 182 LaunchXdgUtility(argv, &exit_code); |
189 return exit_code == 0; | 183 return exit_code == 0; |
190 } | 184 } |
191 | 185 |
192 void DeleteShortcutInApplicationsMenu(const FilePath& shortcut_filename) { | |
193 std::vector<std::string> argv; | |
194 argv.push_back("xdg-desktop-menu"); | |
195 argv.push_back("uninstall"); | |
196 | |
197 // Uninstall in user mode, to match the install. | |
198 argv.push_back("--mode"); | |
199 argv.push_back("user"); | |
200 | |
201 // The file does not need to exist anywhere - xdg-desktop-menu will uninstall | |
202 // items from the menu with a matching name. | |
203 argv.push_back(shortcut_filename.value()); | |
204 int exit_code; | |
205 LaunchXdgUtility(argv, &exit_code); | |
206 } | |
207 | |
208 // Quote a string such that it appears as one verbatim argument for the Exec | 186 // Quote a string such that it appears as one verbatim argument for the Exec |
209 // key in a desktop file. | 187 // key in a desktop file. |
210 std::string QuoteArgForDesktopFileExec(const std::string& arg) { | 188 std::string QuoteArgForDesktopFileExec(const std::string& arg) { |
211 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html | 189 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html |
212 | 190 |
213 // Quoting is only necessary if the argument has a reserved character. | 191 // Quoting is only necessary if the argument has a reserved character. |
214 if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos) | 192 if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos) |
215 return arg; // No quoting necessary. | 193 return arg; // No quoting necessary. |
216 | 194 |
217 std::string quoted = "\""; | 195 std::string quoted = "\""; |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
470 if (file_util::PathExists(path)) { | 448 if (file_util::PathExists(path)) { |
471 VLOG(1) << "Found desktop file template at " << path.value(); | 449 VLOG(1) << "Found desktop file template at " << path.value(); |
472 return file_util::ReadFileToString(path, output); | 450 return file_util::ReadFileToString(path, output); |
473 } | 451 } |
474 } | 452 } |
475 | 453 |
476 LOG(ERROR) << "Could not find desktop file template."; | 454 LOG(ERROR) << "Could not find desktop file template."; |
477 return false; | 455 return false; |
478 } | 456 } |
479 | 457 |
480 FilePath GetWebShortcutFilename(const GURL& url) { | 458 FilePath GetDesktopShortcutFilename(const GURL& url) { |
481 // Use a prefix, because xdg-desktop-menu requires it. | 459 // Use a prefix, because xdg-desktop-menu requires it. |
482 std::string filename = | 460 std::string filename = |
483 std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec(); | 461 std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec(); |
484 file_util::ReplaceIllegalCharactersInPath(&filename, '_'); | 462 file_util::ReplaceIllegalCharactersInPath(&filename, '_'); |
485 | 463 |
486 FilePath desktop_path; | 464 FilePath desktop_path; |
487 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) | 465 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) |
488 return FilePath(); | 466 return FilePath(); |
489 | 467 |
490 FilePath filepath = desktop_path.Append(filename); | 468 FilePath filepath = desktop_path.Append(filename); |
491 FilePath alternative_filepath(filepath.value() + ".desktop"); | 469 FilePath alternative_filepath(filepath.value() + ".desktop"); |
492 for (size_t i = 1; i < 100; ++i) { | 470 for (size_t i = 1; i < 100; ++i) { |
493 if (file_util::PathExists(FilePath(alternative_filepath))) { | 471 if (file_util::PathExists(FilePath(alternative_filepath))) { |
494 alternative_filepath = FilePath( | 472 alternative_filepath = FilePath( |
495 filepath.value() + "_" + base::IntToString(i) + ".desktop"); | 473 filepath.value() + "_" + base::IntToString(i) + ".desktop"); |
496 } else { | 474 } else { |
497 return FilePath(alternative_filepath).BaseName(); | 475 return FilePath(alternative_filepath).BaseName(); |
498 } | 476 } |
499 } | 477 } |
500 | 478 |
501 return FilePath(); | 479 return FilePath(); |
502 } | 480 } |
503 | 481 |
504 FilePath GetExtensionShortcutFilename(const FilePath& profile_path, | |
505 const std::string& extension_id) { | |
506 DCHECK(!extension_id.empty()); | |
507 | |
508 // Use a prefix, because xdg-desktop-menu requires it. | |
509 std::string filename(chrome::kBrowserProcessExecutableName); | |
510 filename.append("-") | |
511 .append(extension_id) | |
512 .append("-") | |
513 .append(profile_path.BaseName().value()); | |
514 file_util::ReplaceIllegalCharactersInPath(&filename, '_'); | |
515 return FilePath(filename.append(".desktop")); | |
516 } | |
517 | |
518 std::string GetDesktopFileContents( | 482 std::string GetDesktopFileContents( |
519 const std::string& template_contents, | 483 const std::string& template_contents, |
520 const std::string& app_name, | 484 const std::string& app_name, |
521 const GURL& url, | 485 const GURL& url, |
522 const std::string& extension_id, | 486 const std::string& extension_id, |
523 const bool is_platform_app, | 487 const bool is_platform_app, |
524 const FilePath& extension_path, | 488 const FilePath& extension_path, |
525 const string16& title, | 489 const string16& title, |
526 const std::string& icon_name, | 490 const std::string& icon_name, |
527 const FilePath& profile_path) { | 491 const FilePath& profile_path) { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 | 590 |
627 g_key_file_free(key_file); | 591 g_key_file_free(key_file); |
628 return output_buffer; | 592 return output_buffer; |
629 } | 593 } |
630 | 594 |
631 bool CreateDesktopShortcut( | 595 bool CreateDesktopShortcut( |
632 const ShellIntegration::ShortcutInfo& shortcut_info, | 596 const ShellIntegration::ShortcutInfo& shortcut_info, |
633 const std::string& shortcut_template) { | 597 const std::string& shortcut_template) { |
634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
635 | 599 |
636 FilePath shortcut_filename; | 600 FilePath shortcut_filename = |
637 if (!shortcut_info.extension_id.empty()) { | 601 ShellIntegrationLinux::GetDesktopShortcutFilename(shortcut_info.url); |
638 shortcut_filename = GetExtensionShortcutFilename( | |
639 shortcut_info.profile_path, shortcut_info.extension_id); | |
640 // For extensions we do not want duplicate shortcuts. So, delete any that | |
641 // already exist and replace them. | |
642 if (shortcut_info.create_on_desktop) | |
643 DeleteShortcutOnDesktop(shortcut_filename); | |
644 if (shortcut_info.create_in_applications_menu) | |
645 DeleteShortcutInApplicationsMenu(shortcut_filename); | |
646 } else { | |
647 shortcut_filename = GetWebShortcutFilename(shortcut_info.url); | |
648 } | |
649 if (shortcut_filename.empty()) | 602 if (shortcut_filename.empty()) |
650 return false; | 603 return false; |
651 | 604 |
652 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); | 605 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); |
653 | 606 |
654 std::string app_name = | 607 std::string app_name = |
655 web_app::GenerateApplicationNameFromInfo(shortcut_info); | 608 web_app::GenerateApplicationNameFromInfo(shortcut_info); |
656 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( | 609 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( |
657 shortcut_template, | 610 shortcut_template, |
658 app_name, | 611 app_name, |
(...skipping 10 matching lines...) Expand all Loading... |
669 if (shortcut_info.create_on_desktop) | 622 if (shortcut_info.create_on_desktop) |
670 success = CreateShortcutOnDesktop(shortcut_filename, contents); | 623 success = CreateShortcutOnDesktop(shortcut_filename, contents); |
671 | 624 |
672 if (shortcut_info.create_in_applications_menu) | 625 if (shortcut_info.create_in_applications_menu) |
673 success = CreateShortcutInApplicationsMenu(shortcut_filename, contents) && | 626 success = CreateShortcutInApplicationsMenu(shortcut_filename, contents) && |
674 success; | 627 success; |
675 | 628 |
676 return success; | 629 return success; |
677 } | 630 } |
678 | 631 |
679 void DeleteDesktopShortcuts(const FilePath& profile_path, | |
680 const std::string& extension_id) { | |
681 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
682 | |
683 FilePath shortcut_filename = GetExtensionShortcutFilename( | |
684 profile_path, extension_id); | |
685 DCHECK(!shortcut_filename.empty()); | |
686 | |
687 DeleteShortcutOnDesktop(shortcut_filename); | |
688 DeleteShortcutInApplicationsMenu(shortcut_filename); | |
689 } | |
690 | |
691 } // namespace ShellIntegrationLinux | 632 } // namespace ShellIntegrationLinux |
OLD | NEW |