Chromium Code Reviews| 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 | |
| 157 bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename, | 163 bool CreateShortcutInApplicationsMenu(const FilePath& shortcut_filename, |
| 158 const std::string& contents) { | 164 const std::string& contents) { |
| 159 ScopedTempDir temp_dir; | 165 ScopedTempDir temp_dir; |
| 160 if (!temp_dir.CreateUniqueTempDir()) | 166 if (!temp_dir.CreateUniqueTempDir()) |
| 161 return false; | 167 return false; |
| 162 | 168 |
| 163 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); | 169 FilePath temp_file_path = temp_dir.path().Append(shortcut_filename); |
| 164 | 170 |
| 165 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), | 171 int bytes_written = file_util::WriteFile(temp_file_path, contents.data(), |
| 166 contents.length()); | 172 contents.length()); |
| 167 | 173 |
| 168 if (bytes_written != static_cast<int>(contents.length())) | 174 if (bytes_written != static_cast<int>(contents.length())) |
| 169 return false; | 175 return false; |
| 170 | 176 |
| 171 std::vector<std::string> argv; | 177 std::vector<std::string> argv; |
| 172 argv.push_back("xdg-desktop-menu"); | 178 argv.push_back("xdg-desktop-menu"); |
| 173 argv.push_back("install"); | 179 argv.push_back("install"); |
| 174 | 180 |
| 175 // Always install in user mode, even if someone runs the browser as root | 181 // Always install in user mode, even if someone runs the browser as root |
| 176 // (people do that). | 182 // (people do that). |
| 177 argv.push_back("--mode"); | 183 argv.push_back("--mode"); |
| 178 argv.push_back("user"); | 184 argv.push_back("user"); |
| 179 | 185 |
| 180 argv.push_back(temp_file_path.value()); | 186 argv.push_back(temp_file_path.value()); |
| 181 int exit_code; | 187 int exit_code; |
| 182 LaunchXdgUtility(argv, &exit_code); | 188 LaunchXdgUtility(argv, &exit_code); |
| 183 return exit_code == 0; | 189 return exit_code == 0; |
| 184 } | 190 } |
| 185 | 191 |
| 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 | |
| 186 // Quote a string such that it appears as one verbatim argument for the Exec | 208 // Quote a string such that it appears as one verbatim argument for the Exec |
| 187 // key in a desktop file. | 209 // key in a desktop file. |
| 188 std::string QuoteArgForDesktopFileExec(const std::string& arg) { | 210 std::string QuoteArgForDesktopFileExec(const std::string& arg) { |
| 189 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html | 211 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html |
| 190 | 212 |
| 191 // Quoting is only necessary if the argument has a reserved character. | 213 // Quoting is only necessary if the argument has a reserved character. |
| 192 if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos) | 214 if (arg.find_first_of(" \t\n\"'\\><~|&;$*?#()`") == std::string::npos) |
| 193 return arg; // No quoting necessary. | 215 return arg; // No quoting necessary. |
| 194 | 216 |
| 195 std::string quoted = "\""; | 217 std::string quoted = "\""; |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 if (file_util::PathExists(path)) { | 470 if (file_util::PathExists(path)) { |
| 449 VLOG(1) << "Found desktop file template at " << path.value(); | 471 VLOG(1) << "Found desktop file template at " << path.value(); |
| 450 return file_util::ReadFileToString(path, output); | 472 return file_util::ReadFileToString(path, output); |
| 451 } | 473 } |
| 452 } | 474 } |
| 453 | 475 |
| 454 LOG(ERROR) << "Could not find desktop file template."; | 476 LOG(ERROR) << "Could not find desktop file template."; |
| 455 return false; | 477 return false; |
| 456 } | 478 } |
| 457 | 479 |
| 458 FilePath GetDesktopShortcutFilename(const GURL& url) { | 480 FilePath GetWebShortcutFilename(const GURL& url) { |
| 459 // Use a prefix, because xdg-desktop-menu requires it. | 481 // Use a prefix, because xdg-desktop-menu requires it. |
| 460 std::string filename = | 482 std::string filename = |
| 461 std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec(); | 483 std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec(); |
| 462 file_util::ReplaceIllegalCharactersInPath(&filename, '_'); | 484 file_util::ReplaceIllegalCharactersInPath(&filename, '_'); |
| 463 | 485 |
| 464 FilePath desktop_path; | 486 FilePath desktop_path; |
| 465 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) | 487 if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path)) |
| 466 return FilePath(); | 488 return FilePath(); |
| 467 | 489 |
| 468 FilePath filepath = desktop_path.Append(filename); | 490 FilePath filepath = desktop_path.Append(filename); |
| 469 FilePath alternative_filepath(filepath.value() + ".desktop"); | 491 FilePath alternative_filepath(filepath.value() + ".desktop"); |
| 470 for (size_t i = 1; i < 100; ++i) { | 492 for (size_t i = 1; i < 100; ++i) { |
| 471 if (file_util::PathExists(FilePath(alternative_filepath))) { | 493 if (file_util::PathExists(FilePath(alternative_filepath))) { |
| 472 alternative_filepath = FilePath( | 494 alternative_filepath = FilePath( |
| 473 filepath.value() + "_" + base::IntToString(i) + ".desktop"); | 495 filepath.value() + "_" + base::IntToString(i) + ".desktop"); |
| 474 } else { | 496 } else { |
| 475 return FilePath(alternative_filepath).BaseName(); | 497 return FilePath(alternative_filepath).BaseName(); |
| 476 } | 498 } |
| 477 } | 499 } |
| 478 | 500 |
| 479 return FilePath(); | 501 return FilePath(); |
| 480 } | 502 } |
| 481 | 503 |
| 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 | |
| 482 std::string GetDesktopFileContents( | 518 std::string GetDesktopFileContents( |
| 483 const std::string& template_contents, | 519 const std::string& template_contents, |
| 484 const std::string& app_name, | 520 const std::string& app_name, |
| 485 const GURL& url, | 521 const GURL& url, |
| 486 const std::string& extension_id, | 522 const std::string& extension_id, |
| 487 const bool is_platform_app, | 523 const bool is_platform_app, |
| 488 const FilePath& extension_path, | 524 const FilePath& extension_path, |
| 489 const string16& title, | 525 const string16& title, |
| 490 const std::string& icon_name, | 526 const std::string& icon_name, |
| 491 const FilePath& profile_path) { | 527 const FilePath& profile_path) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 g_free(exec_c_string); | 581 g_free(exec_c_string); |
| 546 StringTokenizer exec_tokenizer(exec_string, " "); | 582 StringTokenizer exec_tokenizer(exec_string, " "); |
| 547 | 583 |
| 548 std::string final_path; | 584 std::string final_path; |
| 549 while (exec_tokenizer.GetNext() && exec_tokenizer.token() != "%U") { | 585 while (exec_tokenizer.GetNext() && exec_tokenizer.token() != "%U") { |
| 550 if (!final_path.empty()) | 586 if (!final_path.empty()) |
| 551 final_path += " "; | 587 final_path += " "; |
| 552 final_path += exec_tokenizer.token(); | 588 final_path += exec_tokenizer.token(); |
| 553 } | 589 } |
| 554 CommandLine cmd_line(CommandLine::NO_PROGRAM); | 590 CommandLine cmd_line(CommandLine::NO_PROGRAM); |
| 555 cmd_line = ShellIntegration::CommandLineArgsForLauncher( | 591 cmd_line = ShellIntegration::CommandLineArgsForLauncher( |
|
Mihai Parparita -not on Chrome
2012/07/10 22:51:27
Encoding this data in the filename seems ugly (use
benwells
2012/07/10 22:55:51
It's not visible to users. Currently the filename
| |
| 556 url, extension_id, is_platform_app, profile_path); | 592 url, extension_id, is_platform_app, profile_path); |
| 557 const CommandLine::SwitchMap& switch_map = cmd_line.GetSwitches(); | 593 const CommandLine::SwitchMap& switch_map = cmd_line.GetSwitches(); |
| 558 for (CommandLine::SwitchMap::const_iterator i = switch_map.begin(); | 594 for (CommandLine::SwitchMap::const_iterator i = switch_map.begin(); |
| 559 i != switch_map.end(); ++i) { | 595 i != switch_map.end(); ++i) { |
| 560 if (i->second.empty()) { | 596 if (i->second.empty()) { |
| 561 final_path += " --" + i->first; | 597 final_path += " --" + i->first; |
| 562 } else { | 598 } else { |
| 563 final_path += " " + QuoteArgForDesktopFileExec("--" + i->first + | 599 final_path += " " + QuoteArgForDesktopFileExec("--" + i->first + |
| 564 "=" + i->second); | 600 "=" + i->second); |
| 565 } | 601 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 590 | 626 |
| 591 g_key_file_free(key_file); | 627 g_key_file_free(key_file); |
| 592 return output_buffer; | 628 return output_buffer; |
| 593 } | 629 } |
| 594 | 630 |
| 595 bool CreateDesktopShortcut( | 631 bool CreateDesktopShortcut( |
| 596 const ShellIntegration::ShortcutInfo& shortcut_info, | 632 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 597 const std::string& shortcut_template) { | 633 const std::string& shortcut_template) { |
| 598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 599 | 635 |
| 600 FilePath shortcut_filename = | 636 FilePath shortcut_filename; |
| 601 ShellIntegrationLinux::GetDesktopShortcutFilename(shortcut_info.url); | 637 if (!shortcut_info.extension_id.empty()) { |
| 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 } | |
| 602 if (shortcut_filename.empty()) | 649 if (shortcut_filename.empty()) |
| 603 return false; | 650 return false; |
| 604 | 651 |
| 605 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); | 652 std::string icon_name = CreateShortcutIcon(shortcut_info, shortcut_filename); |
| 606 | 653 |
| 607 std::string app_name = | 654 std::string app_name = |
| 608 web_app::GenerateApplicationNameFromInfo(shortcut_info); | 655 web_app::GenerateApplicationNameFromInfo(shortcut_info); |
| 609 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( | 656 std::string contents = ShellIntegrationLinux::GetDesktopFileContents( |
| 610 shortcut_template, | 657 shortcut_template, |
| 611 app_name, | 658 app_name, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 622 if (shortcut_info.create_on_desktop) | 669 if (shortcut_info.create_on_desktop) |
| 623 success = CreateShortcutOnDesktop(shortcut_filename, contents); | 670 success = CreateShortcutOnDesktop(shortcut_filename, contents); |
| 624 | 671 |
| 625 if (shortcut_info.create_in_applications_menu) | 672 if (shortcut_info.create_in_applications_menu) |
| 626 success = CreateShortcutInApplicationsMenu(shortcut_filename, contents) && | 673 success = CreateShortcutInApplicationsMenu(shortcut_filename, contents) && |
| 627 success; | 674 success; |
| 628 | 675 |
| 629 return success; | 676 return success; |
| 630 } | 677 } |
| 631 | 678 |
| 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 | |
| 632 } // namespace ShellIntegrationLinux | 691 } // namespace ShellIntegrationLinux |
| OLD | NEW |