OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "app/l10n_util.h" | 5 #include "app/l10n_util.h" |
6 #include "app/resource_bundle.h" | 6 #include "app/resource_bundle.h" |
7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/file_path.h" | |
10 #include "base/logging.h" | 9 #include "base/logging.h" |
11 #include "base/path_service.h" | |
12 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
13 #include "chrome/app/chrome_command_ids.h" | 11 #include "chrome/app/chrome_command_ids.h" |
14 #include "chrome/browser/background_application_list_model.h" | 12 #include "chrome/browser/background_application_list_model.h" |
15 #include "chrome/browser/background_mode_manager.h" | 13 #include "chrome/browser/background_mode_manager.h" |
16 #include "chrome/browser/browser_list.h" | 14 #include "chrome/browser/browser_list.h" |
17 #include "chrome/browser/extensions/extensions_service.h" | 15 #include "chrome/browser/extensions/extensions_service.h" |
18 #include "chrome/browser/metrics/user_metrics.h" | 16 #include "chrome/browser/metrics/user_metrics.h" |
19 #include "chrome/browser/prefs/pref_service.h" | 17 #include "chrome/browser/prefs/pref_service.h" |
20 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
21 #include "chrome/browser/shell_integration.h" | |
22 #include "chrome/browser/status_icons/status_icon.h" | 19 #include "chrome/browser/status_icons/status_icon.h" |
23 #include "chrome/browser/status_icons/status_tray.h" | 20 #include "chrome/browser/status_icons/status_tray.h" |
24 #include "chrome/common/chrome_switches.h" | 21 #include "chrome/common/chrome_switches.h" |
25 #include "chrome/common/extensions/extension.h" | 22 #include "chrome/common/extensions/extension.h" |
26 #include "chrome/common/notification_service.h" | 23 #include "chrome/common/notification_service.h" |
27 #include "chrome/common/notification_type.h" | 24 #include "chrome/common/notification_type.h" |
28 #include "chrome/common/pref_names.h" | 25 #include "chrome/common/pref_names.h" |
29 #include "grit/browser_resources.h" | |
30 #include "grit/chromium_strings.h" | 26 #include "grit/chromium_strings.h" |
31 #include "grit/generated_resources.h" | 27 #include "grit/generated_resources.h" |
32 #include "grit/theme_resources.h" | 28 #include "grit/theme_resources.h" |
33 | 29 |
34 #if defined(OS_LINUX) | |
35 #include <unistd.h> | |
36 #include "base/environment.h" | |
37 #include "base/file_util.h" | |
38 #include "base/nix/xdg_util.h" | |
39 #include "base/task.h" | |
40 #include "base/utf_string_conversions.h" | |
41 #include "chrome/common/chrome_version_info.h" | |
42 #endif | |
43 | |
44 #if defined(OS_MACOSX) | |
45 #include "base/mac_util.h" | |
46 #endif | |
47 | |
48 #if defined(TOOLKIT_GTK) | |
49 #include "chrome/browser/gtk/gtk_util.h" | |
50 #endif | |
51 | |
52 #if defined(OS_LINUX) | |
53 static const FilePath::CharType kAutostart[] = "autostart"; | |
54 static const FilePath::CharType kConfig[] = ".config"; | |
55 static const char kXdgConfigHome[] = "XDG_CONFIG_HOME"; | |
56 #endif | |
57 | |
58 #if defined(OS_WIN) | |
59 #include "base/win/registry.h" | |
60 const HKEY kBackgroundModeRegistryRootKey = HKEY_CURRENT_USER; | |
61 const wchar_t* kBackgroundModeRegistrySubkey = | |
62 L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; | |
63 const wchar_t* kBackgroundModeRegistryKeyName = L"chromium"; | |
64 #endif | |
65 | |
66 #if defined(OS_LINUX) | |
67 namespace { | |
68 | |
69 FilePath GetAutostartDirectory(base::Environment* environment) { | |
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
71 FilePath result = | |
72 base::nix::GetXDGDirectory(environment, kXdgConfigHome, kConfig); | |
73 result = result.Append(kAutostart); | |
74 return result; | |
75 } | |
76 | |
77 FilePath GetAutostartFilename(base::Environment* environment) { | |
78 FilePath directory = GetAutostartDirectory(environment); | |
79 return directory.Append(ShellIntegration::GetDesktopName(environment)); | |
80 } | |
81 | |
82 } // namespace | |
83 #endif // defined(OS_LINUX) | |
84 | |
85 #if defined(OS_WIN) || defined(OS_LINUX) | |
86 class DisableLaunchOnStartupTask : public Task { | |
87 public: | |
88 virtual void Run() { | |
89 #if defined(OS_LINUX) | |
90 scoped_ptr<base::Environment> environment(base::Environment::Create()); | |
91 if (!file_util::Delete(GetAutostartFilename(environment.get()), false)) { | |
92 LOG(WARNING) << "Failed to deregister launch on login."; | |
93 } | |
94 #elif defined(OS_WIN) | |
95 const wchar_t* key_name = kBackgroundModeRegistryKeyName; | |
96 base::win::RegKey read_key(kBackgroundModeRegistryRootKey, | |
97 kBackgroundModeRegistrySubkey, KEY_READ); | |
98 base::win::RegKey write_key(kBackgroundModeRegistryRootKey, | |
99 kBackgroundModeRegistrySubkey, KEY_WRITE); | |
100 if (read_key.ValueExists(key_name) && !write_key.DeleteValue(key_name)) | |
101 LOG(WARNING) << "Failed to deregister launch on login."; | |
102 #endif | |
103 } | |
104 }; | |
105 #endif // defined(OS_WIN) || defined(OS_LINUX) | |
106 | |
107 // TODO(rickcam): Bug 56280: Share implementation with ShellIntegration | |
108 #if defined(OS_WIN) || defined(OS_LINUX) | |
109 class EnableLaunchOnStartupTask : public Task { | |
110 public: | |
111 virtual void Run() { | |
112 #if defined(OS_LINUX) | |
113 scoped_ptr<base::Environment> environment(base::Environment::Create()); | |
114 scoped_ptr<chrome::VersionInfo> version_info(new chrome::VersionInfo()); | |
115 FilePath autostart_directory = GetAutostartDirectory(environment.get()); | |
116 FilePath autostart_file = GetAutostartFilename(environment.get()); | |
117 if (!file_util::DirectoryExists(autostart_directory) && | |
118 !file_util::CreateDirectory(autostart_directory)) { | |
119 LOG(WARNING) | |
120 << "Failed to register launch on login. No autostart directory."; | |
121 return; | |
122 } | |
123 std::string wrapper_script; | |
124 if (!environment->GetVar("CHROME_WRAPPER", &wrapper_script)) { | |
125 LOG(WARNING) | |
126 << "Failed to register launch on login. CHROME_WRAPPER not set."; | |
127 return; | |
128 } | |
129 std::string autostart_file_contents = | |
130 "[Desktop Entry]\n" | |
131 "Type=Application\n" | |
132 "Terminal=false\n" | |
133 "Exec=" + wrapper_script + | |
134 " --enable-background-mode --no-startup-window\n" | |
135 "Name=" + version_info->Name() + "\n"; | |
136 std::string::size_type content_length = autostart_file_contents.length(); | |
137 if (file_util::WriteFile(autostart_file, autostart_file_contents.c_str(), | |
138 content_length) != | |
139 static_cast<int>(content_length)) { | |
140 LOG(WARNING) << "Failed to register launch on login. Failed to write " | |
141 << autostart_file.value(); | |
142 file_util::Delete(GetAutostartFilename(environment.get()), false); | |
143 } | |
144 #elif defined(OS_WIN) | |
145 // TODO(rickcam): Bug 53597: Make RegKey mockable. | |
146 // TODO(rickcam): Bug 53600: Use distinct registry keys per flavor+profile. | |
147 const wchar_t* key_name = kBackgroundModeRegistryKeyName; | |
148 base::win::RegKey read_key(kBackgroundModeRegistryRootKey, | |
149 kBackgroundModeRegistrySubkey, KEY_READ); | |
150 base::win::RegKey write_key(kBackgroundModeRegistryRootKey, | |
151 kBackgroundModeRegistrySubkey, KEY_WRITE); | |
152 FilePath executable; | |
153 if (!PathService::Get(base::FILE_EXE, &executable)) | |
154 return; | |
155 std::wstring new_value = executable.value() + L" --no-startup-window"; | |
156 if (read_key.ValueExists(key_name)) { | |
157 std::wstring current_value; | |
158 if (read_key.ReadValue(key_name, ¤t_value) && | |
159 (current_value == new_value)) { | |
160 return; | |
161 } | |
162 } | |
163 if (!write_key.WriteValue(key_name, new_value.c_str())) | |
164 LOG(WARNING) << "Failed to register launch on login."; | |
165 #endif | |
166 } | |
167 }; | |
168 #endif // defined(OS_WIN) || defined(OS_LINUX) | |
169 | |
170 void BackgroundModeManager::OnApplicationDataChanged( | 30 void BackgroundModeManager::OnApplicationDataChanged( |
171 const Extension* extension) { | 31 const Extension* extension) { |
172 UpdateContextMenuEntryIcon(extension); | 32 UpdateContextMenuEntryIcon(extension); |
173 } | 33 } |
174 | 34 |
175 void BackgroundModeManager::OnApplicationListChanged() { | 35 void BackgroundModeManager::OnApplicationListChanged() { |
176 UpdateStatusTrayIconContextMenu(); | 36 UpdateStatusTrayIconContextMenu(); |
177 } | 37 } |
178 | 38 |
179 BackgroundModeManager::BackgroundModeManager(Profile* profile, | 39 BackgroundModeManager::BackgroundModeManager(Profile* profile, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 BackgroundModeManager::~BackgroundModeManager() { | 98 BackgroundModeManager::~BackgroundModeManager() { |
239 applications_.RemoveObserver(this); | 99 applications_.RemoveObserver(this); |
240 | 100 |
241 // We're going away, so exit background mode (does nothing if we aren't in | 101 // We're going away, so exit background mode (does nothing if we aren't in |
242 // background mode currently). This is primarily needed for unit tests, | 102 // background mode currently). This is primarily needed for unit tests, |
243 // because in an actual running system we'd get an APP_TERMINATING | 103 // because in an actual running system we'd get an APP_TERMINATING |
244 // notification before being destroyed. | 104 // notification before being destroyed. |
245 EndBackgroundMode(); | 105 EndBackgroundMode(); |
246 } | 106 } |
247 | 107 |
248 bool BackgroundModeManager::IsLaunchOnStartupResetAllowed() { | |
249 return profile_->GetPrefs()->GetBoolean(prefs::kLaunchOnStartupResetAllowed); | |
250 } | |
251 | |
252 void BackgroundModeManager::SetLaunchOnStartupResetAllowed(bool allowed) { | |
253 profile_->GetPrefs()->SetBoolean(prefs::kLaunchOnStartupResetAllowed, | |
254 allowed); | |
255 } | |
256 | |
257 void BackgroundModeManager::Observe(NotificationType type, | 108 void BackgroundModeManager::Observe(NotificationType type, |
258 const NotificationSource& source, | 109 const NotificationSource& source, |
259 const NotificationDetails& details) { | 110 const NotificationDetails& details) { |
260 switch (type.value) { | 111 switch (type.value) { |
261 case NotificationType::EXTENSIONS_READY: | 112 case NotificationType::EXTENSIONS_READY: |
262 // Extensions are loaded, so we don't need to manually keep the browser | 113 // Extensions are loaded, so we don't need to manually keep the browser |
263 // process alive any more when running in no-startup-window mode. | 114 // process alive any more when running in no-startup-window mode. |
264 EndKeepAliveForStartup(); | 115 EndKeepAliveForStartup(); |
265 | 116 |
266 // On a Mac, we use 'login items' mechanism which has user-facing UI so we | 117 // On a Mac, we use 'login items' mechanism which has user-facing UI so we |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 EnableLaunchOnStartup(true); | 224 EnableLaunchOnStartup(true); |
374 } | 225 } |
375 | 226 |
376 void BackgroundModeManager::OnBackgroundAppUninstalled() { | 227 void BackgroundModeManager::OnBackgroundAppUninstalled() { |
377 // When uninstalling a background app, disable launch on startup if | 228 // When uninstalling a background app, disable launch on startup if |
378 // we have no more background apps. | 229 // we have no more background apps. |
379 if (background_app_count_ == 0) | 230 if (background_app_count_ == 0) |
380 EnableLaunchOnStartup(false); | 231 EnableLaunchOnStartup(false); |
381 } | 232 } |
382 | 233 |
383 void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) { | |
384 // This functionality is only defined for default profile, currently. | |
385 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir)) | |
386 return; | |
387 #if defined(OS_WIN) || defined(OS_LINUX) | |
388 if (should_launch) { | |
389 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
390 new EnableLaunchOnStartupTask()); | |
391 } else { | |
392 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
393 new DisableLaunchOnStartupTask()); | |
394 } | |
395 #elif defined(OS_MACOSX) | |
396 if (should_launch) { | |
397 // Return if Chrome is already a Login Item (avoid overriding user choice). | |
398 if (mac_util::CheckLoginItemStatus(NULL)) | |
399 return; | |
400 | |
401 mac_util::AddToLoginItems(true); // Hide on startup. | |
402 | |
403 // Remember we set Login Item, not the user - so we can reset it later. | |
404 SetLaunchOnStartupResetAllowed(true); | |
405 } else { | |
406 // If we didn't set Login Item, don't mess with it. | |
407 if (!IsLaunchOnStartupResetAllowed()) | |
408 return; | |
409 SetLaunchOnStartupResetAllowed(false); | |
410 | |
411 // Check if Chrome is not a login Item, or is a Login Item but w/o 'hidden' | |
412 // flag - most likely user has modified the setting, don't override it. | |
413 bool is_hidden = false; | |
414 if (!mac_util::CheckLoginItemStatus(&is_hidden) || !is_hidden) | |
415 return; | |
416 | |
417 mac_util::RemoveFromLoginItems(); | |
418 } | |
419 #endif | |
420 } | |
421 | |
422 void BackgroundModeManager::CreateStatusTrayIcon() { | 234 void BackgroundModeManager::CreateStatusTrayIcon() { |
423 // Only need status icons on windows/linux. ChromeOS doesn't allow exiting | 235 // Only need status icons on windows/linux. ChromeOS doesn't allow exiting |
424 // Chrome and Mac can use the dock icon instead. | 236 // Chrome and Mac can use the dock icon instead. |
425 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) | 237 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) |
426 if (!status_tray_) | 238 if (!status_tray_) |
427 status_tray_ = profile_->GetStatusTray(); | 239 status_tray_ = profile_->GetStatusTray(); |
428 #endif | 240 #endif |
429 | 241 |
430 // If the platform doesn't support status icons, or we've already created | 242 // If the platform doesn't support status icons, or we've already created |
431 // our status icon, just return. | 243 // our status icon, just return. |
(...skipping 23 matching lines...) Expand all Loading... |
455 | 267 |
456 void BackgroundModeManager::UpdateStatusTrayIconContextMenu() { | 268 void BackgroundModeManager::UpdateStatusTrayIconContextMenu() { |
457 if (!status_icon_) | 269 if (!status_icon_) |
458 return; | 270 return; |
459 | 271 |
460 // Create a context menu item for Chrome. | 272 // Create a context menu item for Chrome. |
461 menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this); | 273 menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this); |
462 // Add About item | 274 // Add About item |
463 menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT, | 275 menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT, |
464 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); | 276 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); |
465 | 277 menu->AddItem(IDC_OPTIONS, GetPreferencesMenuLabel()); |
466 // Add Preferences item | |
467 #if defined(OS_CHROMEOS) | |
468 menu->AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS); | |
469 #elif defined(TOOLKIT_GTK) | |
470 string16 preferences = gtk_util::GetStockPreferencesMenuLabel(); | |
471 if (!preferences.empty()) | |
472 menu->AddItem(IDC_OPTIONS, preferences); | |
473 else | |
474 menu->AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES); | |
475 #else | |
476 menu->AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS); | |
477 #endif | |
478 menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); | 278 menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); |
479 menu->AddSeparator(); | 279 menu->AddSeparator(); |
480 int application_position = 0; | 280 int application_position = 0; |
481 context_menu_application_offset_ = menu->GetItemCount(); | 281 context_menu_application_offset_ = menu->GetItemCount(); |
482 for (ExtensionList::const_iterator cursor = applications_.begin(); | 282 for (ExtensionList::const_iterator cursor = applications_.begin(); |
483 cursor != applications_.end(); | 283 cursor != applications_.end(); |
484 ++cursor, ++application_position) { | 284 ++cursor, ++application_position) { |
485 const SkBitmap* icon = applications_.GetIcon(*cursor); | 285 const SkBitmap* icon = applications_.GetIcon(*cursor); |
486 int sort_position = applications_.GetPosition(*cursor); | 286 int sort_position = applications_.GetPosition(*cursor); |
487 DCHECK(sort_position == application_position); | 287 DCHECK(sort_position == application_position); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 Browser* BackgroundModeManager::GetBrowserWindow() { | 353 Browser* BackgroundModeManager::GetBrowserWindow() { |
554 Browser* browser = BrowserList::GetLastActive(); | 354 Browser* browser = BrowserList::GetLastActive(); |
555 if (!browser) { | 355 if (!browser) { |
556 Browser::OpenEmptyWindow(profile_); | 356 Browser::OpenEmptyWindow(profile_); |
557 browser = BrowserList::GetLastActive(); | 357 browser = BrowserList::GetLastActive(); |
558 } | 358 } |
559 return browser; | 359 return browser; |
560 } | 360 } |
561 | 361 |
562 // static | 362 // static |
563 void BackgroundModeManager::RegisterUserPrefs(PrefService* prefs) { | |
564 prefs->RegisterBooleanPref(prefs::kLaunchOnStartupResetAllowed, false); | |
565 } | |
566 | |
567 // static | |
568 bool BackgroundModeManager::IsBackgroundModeEnabled( | 363 bool BackgroundModeManager::IsBackgroundModeEnabled( |
569 const CommandLine* command_line) { | 364 const CommandLine* command_line) { |
570 | 365 |
571 // Background mode is disabled if the appropriate flag is passed, or if | 366 // Background mode is disabled if the appropriate flag is passed, or if |
572 // extensions are disabled. | 367 // extensions are disabled. |
573 bool background_mode_enabled = | 368 bool background_mode_enabled = |
574 !command_line->HasSwitch(switches::kDisableBackgroundMode) && | 369 !command_line->HasSwitch(switches::kDisableBackgroundMode) && |
575 !command_line->HasSwitch(switches::kDisableExtensions); | 370 !command_line->HasSwitch(switches::kDisableExtensions); |
576 #if !defined(OS_WIN) | 371 #if !defined(OS_WIN) |
577 // BackgroundMode is enabled by default on windows. On other platforms, it | 372 // BackgroundMode is enabled by default on windows. On other platforms, it |
578 // is enabled via about:flags. | 373 // is enabled via about:flags. |
579 background_mode_enabled = background_mode_enabled && | 374 background_mode_enabled = background_mode_enabled && |
580 command_line->HasSwitch(switches::kEnableBackgroundMode); | 375 command_line->HasSwitch(switches::kEnableBackgroundMode); |
581 #endif | 376 #endif |
582 | 377 |
583 return background_mode_enabled; | 378 return background_mode_enabled; |
584 } | 379 } |
585 | 380 |
OLD | NEW |