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

Side by Side Diff: chrome/browser/shell_integration_linux.cc

Issue 10698114: Remove app shortcuts when app is uninstalled on Linux. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments Created 8 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698