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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/browser_command_controller.h"
6
7 #include <stddef.h>
8
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/debug/debugging_buildflags.h"
14 #include "base/debug/profiler.h"
15 #include "base/macros.h"
16 #include "base/metrics/user_metrics.h"
17 #include "base/stl_util.h"
18 #include "build/branding_buildflags.h"
19 #include "build/build_config.h"
20 #include "chrome/app/chrome_command_ids.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/defaults.h"
24 #include "chrome/browser/devtools/devtools_window.h"
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/browser/lifetime/application_lifetime.h"
27 #include "chrome/browser/prefs/incognito_mode_prefs.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/profiles/profile_manager.h"
30 #include "chrome/browser/sessions/tab_restore_service_factory.h"
31 #include "chrome/browser/shell_integration.h"
32 #include "chrome/browser/signin/signin_promo.h"
33 #include "chrome/browser/sync/profile_sync_service_factory.h"
34 #include "chrome/browser/ui/apps/app_info_dialog.h"
35 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
36 #include "chrome/browser/ui/browser.h"
37 #include "chrome/browser/ui/browser_commands.h"
38 #include "chrome/browser/ui/browser_finder.h"
39 #include "chrome/browser/ui/browser_window.h"
40 #include "chrome/browser/ui/chrome_pages.h"
41 #include "chrome/browser/ui/commander/commander.h"
42 #include "chrome/browser/ui/page_info/page_info_dialog.h"
43 #include "chrome/browser/ui/singleton_tabs.h"
44 #include "chrome/browser/ui/tabs/tab_strip_model.h"
45 #include "chrome/browser/ui/ui_features.h"
46 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
47 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
48 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
49 #include "chrome/browser/ui/webui/inspect_ui.h"
50 #include "chrome/common/content_restriction.h"
51 #include "chrome/common/pref_names.h"
52 #include "chrome/common/url_constants.h"
53 #include "components/bookmarks/common/bookmark_pref_names.h"
54 #include "components/dom_distiller/core/dom_distiller_features.h"
55 #include "components/prefs/pref_service.h"
56 #include "components/sessions/core/tab_restore_service.h"
57 #include "components/signin/public/base/signin_pref_names.h"
58 #include "content/public/browser/native_web_keyboard_event.h"
59 #include "content/public/browser/navigation_controller.h"
60 #include "content/public/browser/navigation_entry.h"
61 #include "content/public/browser/render_frame_host.h"
62 #include "content/public/browser/web_contents.h"
63 #include "content/public/browser/web_contents_observer.h"
64 #include "content/public/common/profiling.h"
65 #include "content/public/common/url_constants.h"
66 #include "extensions/browser/extension_system.h"
67 #include "printing/buildflags/buildflags.h"
68 #include "ui/events/keycodes/keyboard_codes.h"
69
70 #if defined(OS_MAC)
71 #include "chrome/browser/ui/browser_commands_mac.h"
72 #endif
73
74 #if defined(OS_WIN)
75 #include "base/win/windows_version.h"
76 #include "content/public/browser/gpu_data_manager.h"
77 #endif
78
79 #if defined(OS_CHROMEOS)
80 #include "chrome/browser/platform_util.h"
81 #include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"
82 #include "chrome/browser/ui/browser_commands_chromeos.h"
83 #include "components/session_manager/core/session_manager.h"
84 #endif
85
86 #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_BSD)
87 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
88 #endif
89
90 #if defined(USE_OZONE)
91 #include "ui/base/ui_base_features.h"
92 #include "ui/ozone/public/ozone_platform.h"
93 #endif
94
95 using content::NavigationController;
96 using content::NavigationEntry;
97 using content::WebContents;
98
99 namespace chrome {
100
101 namespace {
102
103 // Ensures that - if we have not popped up an infobar to prompt the user to e.g.
104 // reload the current page - that the content pane of the browser is refocused.
AppInfoDialogClosedCallback(content::WebContents * web_contents,views::Widget::ClosedReason closed_reason,bool reload_prompt)105 void AppInfoDialogClosedCallback(content::WebContents* web_contents,
106 views::Widget::ClosedReason closed_reason,
107 bool reload_prompt) {
108 if (reload_prompt)
109 return;
110
111 // If the user clicked on something specific or focus was changed, don't
112 // override the focus.
113 if (closed_reason != views::Widget::ClosedReason::kEscKeyPressed &&
114 closed_reason != views::Widget::ClosedReason::kCloseButtonClicked) {
115 return;
116 }
117
118 // Ensure that the web contents handle we have is still valid. It's possible
119 // (though unlikely) that either the browser or web contents has been pulled
120 // out from underneath us.
121 Browser* const browser = chrome::FindBrowserWithWebContents(web_contents);
122 if (!browser)
123 return;
124
125 // We want to focus the active web contents, which again, might not be the
126 // original web contents (though it should be the vast majority of the time).
127 content::WebContents* const active_contents =
128 browser->tab_strip_model()->GetActiveWebContents();
129 if (active_contents)
130 active_contents->Focus();
131 }
132
133 } // namespace
134
135 ///////////////////////////////////////////////////////////////////////////////
136 // BrowserCommandController, public:
137
BrowserCommandController(Browser * browser)138 BrowserCommandController::BrowserCommandController(Browser* browser)
139 : browser_(browser), command_updater_(nullptr) {
140 browser_->tab_strip_model()->AddObserver(this);
141 PrefService* local_state = g_browser_process->local_state();
142 if (local_state) {
143 local_pref_registrar_.Init(local_state);
144 local_pref_registrar_.Add(
145 prefs::kAllowFileSelectionDialogs,
146 base::Bind(
147 &BrowserCommandController::UpdateCommandsForFileSelectionDialogs,
148 base::Unretained(this)));
149 }
150
151 profile_pref_registrar_.Init(profile()->GetPrefs());
152 profile_pref_registrar_.Add(
153 prefs::kDevToolsAvailability,
154 base::Bind(&BrowserCommandController::UpdateCommandsForDevTools,
155 base::Unretained(this)));
156 profile_pref_registrar_.Add(
157 bookmarks::prefs::kEditBookmarksEnabled,
158 base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkEditing,
159 base::Unretained(this)));
160 profile_pref_registrar_.Add(
161 bookmarks::prefs::kShowBookmarkBar,
162 base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkBar,
163 base::Unretained(this)));
164 profile_pref_registrar_.Add(
165 prefs::kIncognitoModeAvailability,
166 base::Bind(
167 &BrowserCommandController::UpdateCommandsForIncognitoAvailability,
168 base::Unretained(this)));
169 profile_pref_registrar_.Add(
170 prefs::kPrintingEnabled,
171 base::Bind(&BrowserCommandController::UpdatePrintingState,
172 base::Unretained(this)));
173 #if !defined(OS_MAC)
174 profile_pref_registrar_.Add(
175 prefs::kFullscreenAllowed,
176 base::Bind(&BrowserCommandController::UpdateCommandsForFullscreenMode,
177 base::Unretained(this)));
178 #endif
179 pref_signin_allowed_.Init(
180 prefs::kSigninAllowed, profile()->GetOriginalProfile()->GetPrefs(),
181 base::BindRepeating(&BrowserCommandController::OnSigninAllowedPrefChange,
182 base::Unretained(this)));
183
184 InitCommandState();
185
186 sessions::TabRestoreService* tab_restore_service =
187 TabRestoreServiceFactory::GetForProfile(profile());
188 if (tab_restore_service) {
189 tab_restore_service->AddObserver(this);
190 if (!tab_restore_service->IsLoaded())
191 tab_restore_service->LoadTabsFromLastSession();
192 }
193 }
194
~BrowserCommandController()195 BrowserCommandController::~BrowserCommandController() {
196 // TabRestoreService may have been shutdown by the time we get here. Don't
197 // trigger creating it.
198 sessions::TabRestoreService* tab_restore_service =
199 TabRestoreServiceFactory::GetForProfileIfExisting(profile());
200 if (tab_restore_service)
201 tab_restore_service->RemoveObserver(this);
202 profile_pref_registrar_.RemoveAll();
203 local_pref_registrar_.RemoveAll();
204 browser_->tab_strip_model()->RemoveObserver(this);
205 }
206
IsReservedCommandOrKey(int command_id,const content::NativeWebKeyboardEvent & event)207 bool BrowserCommandController::IsReservedCommandOrKey(
208 int command_id,
209 const content::NativeWebKeyboardEvent& event) {
210 // In Apps mode, no keys are reserved.
211 if (browser_->is_type_app() || browser_->is_type_app_popup())
212 return false;
213
214 #if defined(OS_CHROMEOS)
215 // On Chrome OS, the top row of keys are mapped to browser actions like
216 // back/forward or refresh. We don't want web pages to be able to change the
217 // behavior of these keys. Ash handles F4 and up; this leaves us needing to
218 // reserve browser back/forward and refresh here.
219 ui::KeyboardCode key_code =
220 static_cast<ui::KeyboardCode>(event.windows_key_code);
221 if ((key_code == ui::VKEY_BROWSER_BACK && command_id == IDC_BACK) ||
222 (key_code == ui::VKEY_BROWSER_FORWARD && command_id == IDC_FORWARD) ||
223 (key_code == ui::VKEY_BROWSER_REFRESH && command_id == IDC_RELOAD)) {
224 return true;
225 }
226 #endif
227
228 if (window()->IsFullscreen()) {
229 // In fullscreen, all commands except for IDC_FULLSCREEN and IDC_EXIT should
230 // be delivered to the web page. The intent to implement and ship can be
231 // found in http://crbug.com/680809.
232 const bool is_exit_fullscreen =
233 (command_id == IDC_EXIT || command_id == IDC_FULLSCREEN);
234 #if defined(OS_MAC)
235 // This behavior is different on Mac OS, which has a unique user-initiated
236 // full-screen mode. According to the discussion in http://crbug.com/702251,
237 // the commands should be reserved for browser-side handling if the browser
238 // window's toolbar is visible.
239 if (window()->IsToolbarShowing()) {
240 if (command_id == IDC_FULLSCREEN)
241 return true;
242 } else {
243 return is_exit_fullscreen;
244 }
245 #else
246 return is_exit_fullscreen;
247 #endif
248 }
249
250 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS)
251 // If this key was registered by the user as a content editing hotkey, then
252 // it is not reserved.
253 ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
254 ui::GetTextEditKeyBindingsDelegate();
255 if (delegate && event.os_event && delegate->MatchEvent(*event.os_event, NULL))
256 return false;
257 #endif
258
259 return command_id == IDC_CLOSE_TAB || command_id == IDC_CLOSE_WINDOW ||
260 command_id == IDC_NEW_INCOGNITO_WINDOW || command_id == IDC_NEW_TAB ||
261 command_id == IDC_NEW_WINDOW || command_id == IDC_RESTORE_TAB ||
262 command_id == IDC_SELECT_NEXT_TAB ||
263 command_id == IDC_SELECT_PREVIOUS_TAB || command_id == IDC_EXIT;
264 }
265
TabStateChanged()266 void BrowserCommandController::TabStateChanged() {
267 UpdateCommandsForTabState();
268 UpdateCommandsForWebContentsFocus();
269 }
270
ZoomStateChanged()271 void BrowserCommandController::ZoomStateChanged() {
272 UpdateCommandsForZoomState();
273 }
274
ContentRestrictionsChanged()275 void BrowserCommandController::ContentRestrictionsChanged() {
276 UpdateCommandsForContentRestrictionState();
277 }
278
FullscreenStateChanged()279 void BrowserCommandController::FullscreenStateChanged() {
280 UpdateCommandsForFullscreenMode();
281 }
282
283 #if defined(OS_CHROMEOS)
LockedFullscreenStateChanged()284 void BrowserCommandController::LockedFullscreenStateChanged() {
285 UpdateCommandsForLockedFullscreenMode();
286 }
287 #endif
288
PrintingStateChanged()289 void BrowserCommandController::PrintingStateChanged() {
290 UpdatePrintingState();
291 }
292
LoadingStateChanged(bool is_loading,bool force)293 void BrowserCommandController::LoadingStateChanged(bool is_loading,
294 bool force) {
295 UpdateReloadStopState(is_loading, force);
296 }
297
FindBarVisibilityChanged()298 void BrowserCommandController::FindBarVisibilityChanged() {
299 if (is_locked_fullscreen_)
300 return;
301 UpdateCloseFindOrStop();
302 }
303
ExtensionStateChanged()304 void BrowserCommandController::ExtensionStateChanged() {
305 // Extensions may disable the bookmark editing commands.
306 UpdateCommandsForBookmarkEditing();
307 }
308
TabKeyboardFocusChangedTo(base::Optional<int> index)309 void BrowserCommandController::TabKeyboardFocusChangedTo(
310 base::Optional<int> index) {
311 UpdateCommandsForTabKeyboardFocus(index);
312 }
313
WebContentsFocusChanged()314 void BrowserCommandController::WebContentsFocusChanged() {
315 UpdateCommandsForWebContentsFocus();
316 }
317
318 ////////////////////////////////////////////////////////////////////////////////
319 // BrowserCommandController, CommandUpdater implementation:
320
SupportsCommand(int id) const321 bool BrowserCommandController::SupportsCommand(int id) const {
322 return command_updater_.SupportsCommand(id);
323 }
324
IsCommandEnabled(int id) const325 bool BrowserCommandController::IsCommandEnabled(int id) const {
326 return command_updater_.IsCommandEnabled(id);
327 }
328
ExecuteCommand(int id,base::TimeTicks time_stamp)329 bool BrowserCommandController::ExecuteCommand(int id,
330 base::TimeTicks time_stamp) {
331 return ExecuteCommandWithDisposition(id, WindowOpenDisposition::CURRENT_TAB,
332 time_stamp);
333 }
334
ExecuteCommandWithDisposition(int id,WindowOpenDisposition disposition,base::TimeTicks time_stamp)335 bool BrowserCommandController::ExecuteCommandWithDisposition(
336 int id,
337 WindowOpenDisposition disposition,
338 base::TimeTicks time_stamp) {
339 // Doesn't go through the command_updater_ to avoid dealing with having a
340 // naming collision for ExecuteCommandWithDisposition (both
341 // CommandUpdaterDelegate and CommandUpdater declare this function so we
342 // choose to not implement CommandUpdaterDelegate inside this class and
343 // therefore command_updater_ doesn't have the delegate set).
344 if (!SupportsCommand(id) || !IsCommandEnabled(id))
345 return false;
346
347 // No commands are enabled if there is not yet any selected tab.
348 // TODO(pkasting): It seems like we should not need this, because either
349 // most/all commands should not have been enabled yet anyway or the ones that
350 // are enabled should be global, or safe themselves against having no selected
351 // tab. However, Ben says he tried removing this before and got lots of
352 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
353 // window construction. This probably could use closer examination someday.
354 if (browser_->tab_strip_model()->active_index() == TabStripModel::kNoTab)
355 return true;
356
357 DCHECK(command_updater_.IsCommandEnabled(id))
358 << "Invalid/disabled command " << id;
359
360 // The order of commands in this switch statement must match the function
361 // declaration order in browser.h!
362 switch (id) {
363 // Navigation commands
364 case IDC_BACK:
365 GoBack(browser_, disposition);
366 break;
367 case IDC_FORWARD:
368 GoForward(browser_, disposition);
369 break;
370 case IDC_RELOAD:
371 Reload(browser_, disposition);
372 break;
373 case IDC_RELOAD_CLEARING_CACHE:
374 ClearCache(browser_);
375 FALLTHROUGH;
376 case IDC_RELOAD_BYPASSING_CACHE:
377 ReloadBypassingCache(browser_, disposition);
378 break;
379 case IDC_HOME:
380 Home(browser_, disposition);
381 break;
382 case IDC_OPEN_CURRENT_URL:
383 OpenCurrentURL(browser_);
384 break;
385 case IDC_STOP:
386 Stop(browser_);
387 break;
388 case IDC_TAB_SEARCH:
389 ShowTabSearch(browser_);
390 break;
391 case IDC_TAB_SEARCH_CLOSE:
392 CloseTabSearch(browser_);
393 break;
394
395 // Window management commands
396 case IDC_NEW_WINDOW:
397 NewWindow(browser_);
398 break;
399 case IDC_NEW_INCOGNITO_WINDOW:
400 NewIncognitoWindow(profile());
401 break;
402 case IDC_CLOSE_WINDOW:
403 base::RecordAction(base::UserMetricsAction("CloseWindowByKey"));
404 CloseWindow(browser_);
405 break;
406 case IDC_NEW_TAB: {
407 NewTab(browser_);
408 break;
409 }
410 case IDC_CLOSE_TAB:
411 base::RecordAction(base::UserMetricsAction("CloseTabByKey"));
412 CloseTab(browser_);
413 break;
414 case IDC_SELECT_NEXT_TAB:
415 base::RecordAction(base::UserMetricsAction("Accel_SelectNextTab"));
416 SelectNextTab(browser_,
417 {TabStripModel::GestureType::kKeyboard, time_stamp});
418 break;
419 case IDC_SELECT_PREVIOUS_TAB:
420 base::RecordAction(base::UserMetricsAction("Accel_SelectPreviousTab"));
421 SelectPreviousTab(browser_,
422 {TabStripModel::GestureType::kKeyboard, time_stamp});
423 break;
424 case IDC_MOVE_TAB_NEXT:
425 MoveTabNext(browser_);
426 break;
427 case IDC_MOVE_TAB_PREVIOUS:
428 MoveTabPrevious(browser_);
429 break;
430 case IDC_SELECT_TAB_0:
431 case IDC_SELECT_TAB_1:
432 case IDC_SELECT_TAB_2:
433 case IDC_SELECT_TAB_3:
434 case IDC_SELECT_TAB_4:
435 case IDC_SELECT_TAB_5:
436 case IDC_SELECT_TAB_6:
437 case IDC_SELECT_TAB_7:
438 base::RecordAction(base::UserMetricsAction("Accel_SelectNumberedTab"));
439 SelectNumberedTab(browser_, id - IDC_SELECT_TAB_0,
440 {TabStripModel::GestureType::kKeyboard, time_stamp});
441 break;
442 case IDC_SELECT_LAST_TAB:
443 base::RecordAction(base::UserMetricsAction("Accel_SelectNumberedTab"));
444 SelectLastTab(browser_,
445 {TabStripModel::GestureType::kKeyboard, time_stamp});
446 break;
447 case IDC_DUPLICATE_TAB:
448 DuplicateTab(browser_);
449 break;
450 case IDC_RESTORE_TAB:
451 RestoreTab(browser_);
452 browser_->window()->OnTabRestored(IDC_RESTORE_TAB);
453 break;
454 case IDC_SHOW_AS_TAB:
455 ConvertPopupToTabbedBrowser(browser_);
456 break;
457 case IDC_FULLSCREEN:
458 chrome::ToggleFullscreenMode(browser_);
459 break;
460 case IDC_OPEN_IN_PWA_WINDOW:
461 base::RecordAction(base::UserMetricsAction("OpenActiveTabInPwaWindow"));
462 web_app::ReparentWebAppForActiveTab(browser_);
463 break;
464 case IDC_MOVE_TAB_TO_NEW_WINDOW:
465 MoveActiveTabToNewWindow(browser_);
466 break;
467 case IDC_NAME_WINDOW:
468 PromptToNameWindow(browser_);
469 break;
470
471 #if defined(OS_CHROMEOS)
472 case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
473 case IDC_VISIT_DESKTOP_OF_LRU_USER_3:
474 case IDC_VISIT_DESKTOP_OF_LRU_USER_4:
475 case IDC_VISIT_DESKTOP_OF_LRU_USER_5:
476 ExecuteVisitDesktopCommand(id, window()->GetNativeWindow());
477 break;
478 #endif
479
480 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS)
481 case IDC_MINIMIZE_WINDOW:
482 browser_->window()->Minimize();
483 break;
484 case IDC_MAXIMIZE_WINDOW:
485 browser_->window()->Maximize();
486 break;
487 case IDC_RESTORE_WINDOW:
488 browser_->window()->Restore();
489 break;
490 case IDC_USE_SYSTEM_TITLE_BAR: {
491 PrefService* prefs = profile()->GetPrefs();
492 prefs->SetBoolean(prefs::kUseCustomChromeFrame,
493 !prefs->GetBoolean(prefs::kUseCustomChromeFrame));
494 break;
495 }
496 #endif
497
498 #if defined(OS_MAC)
499 case IDC_TOGGLE_FULLSCREEN_TOOLBAR:
500 chrome::ToggleFullscreenToolbar(browser_);
501 break;
502 case IDC_TOGGLE_JAVASCRIPT_APPLE_EVENTS: {
503 chrome::ToggleJavaScriptFromAppleEventsAllowed(browser_);
504 break;
505 }
506 #endif
507 case IDC_EXIT:
508 Exit();
509 break;
510
511 // Page-related commands
512 case IDC_SAVE_PAGE:
513 SavePage(browser_);
514 break;
515 case IDC_BOOKMARK_THIS_TAB:
516 BookmarkCurrentTab(browser_);
517 break;
518 case IDC_BOOKMARK_ALL_TABS:
519 BookmarkAllTabs(browser_);
520 break;
521 case IDC_VIEW_SOURCE:
522 browser_->tab_strip_model()
523 ->GetActiveWebContents()
524 ->GetMainFrame()
525 ->ViewSource();
526 break;
527 case IDC_PRINT:
528 Print(browser_);
529 break;
530
531 #if BUILDFLAG(ENABLE_PRINTING)
532 case IDC_BASIC_PRINT:
533 base::RecordAction(base::UserMetricsAction("Accel_Advanced_Print"));
534 BasicPrint(browser_);
535 break;
536 #endif // ENABLE_PRINTING
537
538 case IDC_SAVE_CREDIT_CARD_FOR_PAGE:
539 SaveCreditCard(browser_);
540 break;
541 case IDC_MIGRATE_LOCAL_CREDIT_CARD_FOR_PAGE:
542 MigrateLocalCards(browser_);
543 break;
544 case IDC_SHOW_SAVE_LOCAL_CARD_SIGN_IN_PROMO_IF_APPLICABLE:
545 MaybeShowSaveLocalCardSignInPromo(browser_);
546 break;
547 case IDC_CLOSE_SIGN_IN_PROMO:
548 CloseSaveLocalCardSignInPromo(browser_);
549 break;
550 case IDC_TRANSLATE_PAGE:
551 Translate(browser_);
552 break;
553 case IDC_MANAGE_PASSWORDS_FOR_PAGE:
554 ManagePasswordsForPage(browser_);
555 break;
556 case IDC_SEND_TAB_TO_SELF:
557 SendTabToSelfFromPageAction(browser_);
558 break;
559 case IDC_QRCODE_GENERATOR:
560 GenerateQRCodeFromPageAction(browser_);
561 break;
562
563 // Clipboard commands
564 case IDC_CUT:
565 case IDC_COPY:
566 case IDC_PASTE:
567 CutCopyPaste(browser_, id);
568 break;
569
570 // Find-in-page
571 case IDC_FIND:
572 Find(browser_);
573 break;
574 case IDC_FIND_NEXT:
575 FindNext(browser_);
576 break;
577 case IDC_FIND_PREVIOUS:
578 FindPrevious(browser_);
579 break;
580 case IDC_CLOSE_FIND_OR_STOP:
581 if (CanCloseFind(browser_))
582 CloseFind(browser_);
583 else if (IsCommandEnabled(IDC_STOP))
584 ExecuteCommand(IDC_STOP);
585 break;
586
587 // Zoom
588 case IDC_ZOOM_PLUS:
589 Zoom(browser_, content::PAGE_ZOOM_IN);
590 break;
591 case IDC_ZOOM_NORMAL:
592 Zoom(browser_, content::PAGE_ZOOM_RESET);
593 break;
594 case IDC_ZOOM_MINUS:
595 Zoom(browser_, content::PAGE_ZOOM_OUT);
596 break;
597
598 // Focus various bits of UI
599 case IDC_FOCUS_TOOLBAR:
600 base::RecordAction(base::UserMetricsAction("Accel_Focus_Toolbar"));
601 FocusToolbar(browser_);
602 break;
603 case IDC_FOCUS_LOCATION:
604 base::RecordAction(base::UserMetricsAction("Accel_Focus_Location"));
605 FocusLocationBar(browser_);
606 break;
607 case IDC_FOCUS_SEARCH:
608 base::RecordAction(base::UserMetricsAction("Accel_Focus_Search"));
609 FocusSearch(browser_);
610 break;
611 case IDC_FOCUS_MENU_BAR:
612 FocusAppMenu(browser_);
613 break;
614 case IDC_FOCUS_BOOKMARKS:
615 base::RecordAction(base::UserMetricsAction("Accel_Focus_Bookmarks"));
616 FocusBookmarksToolbar(browser_);
617 break;
618 case IDC_FOCUS_INACTIVE_POPUP_FOR_ACCESSIBILITY:
619 FocusInactivePopupForAccessibility(browser_);
620 break;
621 case IDC_FOCUS_NEXT_PANE:
622 FocusNextPane(browser_);
623 break;
624 case IDC_FOCUS_PREVIOUS_PANE:
625 FocusPreviousPane(browser_);
626 break;
627
628 // Show various bits of UI
629 case IDC_OPEN_FILE:
630 browser_->OpenFile();
631 break;
632 case IDC_CREATE_SHORTCUT:
633 base::RecordAction(base::UserMetricsAction("CreateShortcut"));
634 web_app::CreateWebAppFromCurrentWebContents(
635 browser_, true /* force_shortcut_app */);
636 break;
637 case IDC_INSTALL_PWA:
638 base::RecordAction(base::UserMetricsAction("InstallWebAppFromMenu"));
639 web_app::CreateWebAppFromCurrentWebContents(
640 browser_, false /* force_shortcut_app */);
641 break;
642 case IDC_DEV_TOOLS:
643 ToggleDevToolsWindow(browser_, DevToolsToggleAction::Show(),
644 DevToolsOpenedByAction::kMainMenuOrMainShortcut);
645 break;
646 case IDC_DEV_TOOLS_CONSOLE:
647 ToggleDevToolsWindow(browser_, DevToolsToggleAction::ShowConsolePanel(),
648 DevToolsOpenedByAction::kConsoleShortcut);
649 break;
650 case IDC_DEV_TOOLS_DEVICES:
651 InspectUI::InspectDevices(browser_);
652 break;
653 case IDC_DEV_TOOLS_INSPECT:
654 ToggleDevToolsWindow(browser_, DevToolsToggleAction::Inspect(),
655 DevToolsOpenedByAction::kInspectorModeShortcut);
656 break;
657 case IDC_DEV_TOOLS_TOGGLE:
658 ToggleDevToolsWindow(browser_, DevToolsToggleAction::Toggle(),
659 DevToolsOpenedByAction::kToggleShortcut);
660 break;
661 case IDC_TASK_MANAGER:
662 OpenTaskManager(browser_);
663 break;
664 #if defined(OS_CHROMEOS)
665 case IDC_TAKE_SCREENSHOT:
666 TakeScreenshot();
667 break;
668 #endif
669 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
670 case IDC_FEEDBACK:
671 OpenFeedbackDialog(browser_, kFeedbackSourceBrowserCommand);
672 break;
673 #endif
674 case IDC_SHOW_BOOKMARK_BAR:
675 ToggleBookmarkBar(browser_);
676 break;
677 case IDC_SHOW_FULL_URLS:
678 ToggleShowFullURLs(browser_);
679 break;
680 case IDC_PROFILING_ENABLED:
681 content::Profiling::Toggle();
682 break;
683 case IDC_CARET_BROWSING_TOGGLE:
684 ToggleCaretBrowsing(browser_);
685 break;
686
687 case IDC_SHOW_BOOKMARK_MANAGER:
688 ShowBookmarkManager(browser_);
689 break;
690 case IDC_SHOW_APP_MENU:
691 base::RecordAction(base::UserMetricsAction("Accel_Show_App_Menu"));
692 ShowAppMenu(browser_);
693 break;
694 case IDC_SHOW_AVATAR_MENU:
695 ShowAvatarMenu(browser_);
696 break;
697 case IDC_SHOW_HISTORY:
698 ShowHistory(browser_);
699 break;
700 case IDC_SHOW_DOWNLOADS:
701 ShowDownloads(browser_);
702 break;
703 case IDC_MANAGE_EXTENSIONS:
704 ShowExtensions(browser_, std::string());
705 break;
706 case IDC_OPTIONS:
707 ShowSettings(browser_);
708 break;
709 case IDC_EDIT_SEARCH_ENGINES:
710 ShowSearchEngineSettings(browser_);
711 break;
712 case IDC_VIEW_PASSWORDS:
713 ShowPasswordManager(browser_);
714 break;
715 case IDC_CLEAR_BROWSING_DATA:
716 ShowClearBrowsingDataDialog(browser_);
717 break;
718 case IDC_IMPORT_SETTINGS:
719 ShowImportDialog(browser_);
720 break;
721 case IDC_TOGGLE_REQUEST_TABLET_SITE:
722 ToggleRequestTabletSite(browser_);
723 break;
724 case IDC_ABOUT:
725 ShowAboutChrome(browser_);
726 break;
727 case IDC_UPGRADE_DIALOG:
728 OpenUpdateChromeDialog(browser_);
729 break;
730 case IDC_HELP_PAGE_VIA_KEYBOARD:
731 ShowHelp(browser_, HELP_SOURCE_KEYBOARD);
732 break;
733 case IDC_HELP_PAGE_VIA_MENU:
734 ShowHelp(browser_, HELP_SOURCE_MENU);
735 break;
736 case IDC_SHOW_BETA_FORUM:
737 ShowBetaForum(browser_);
738 break;
739 case IDC_TOGGLE_COMMANDER:
740 ToggleCommander(browser_);
741 break;
742 #if !defined(OS_CHROMEOS)
743 case IDC_SHOW_SIGNIN:
744 ShowBrowserSigninOrSettings(
745 browser_, signin_metrics::AccessPoint::ACCESS_POINT_MENU);
746 break;
747 #endif
748 case IDC_DISTILL_PAGE:
749 ToggleDistilledView(browser_);
750 break;
751 case IDC_ROUTE_MEDIA:
752 RouteMediaInvokedFromAppMenu(browser_);
753 break;
754 case IDC_WINDOW_MUTE_SITE:
755 MuteSite(browser_);
756 break;
757 case IDC_WINDOW_PIN_TAB:
758 PinTab(browser_);
759 break;
760 case IDC_WINDOW_GROUP_TAB:
761 GroupTab(browser_);
762 break;
763 case IDC_WINDOW_CLOSE_TABS_TO_RIGHT:
764 CloseTabsToRight(browser_);
765 break;
766 case IDC_WINDOW_CLOSE_OTHER_TABS:
767 CloseOtherTabs(browser_);
768 break;
769 case IDC_SHOW_MANAGEMENT_PAGE: {
770 ShowSingletonTab(browser_, GURL(kChromeUIManagementURL));
771 break;
772 }
773 case IDC_MUTE_TARGET_SITE:
774 MuteSiteForKeyboardFocusedTab(browser_);
775 break;
776 case IDC_PIN_TARGET_TAB:
777 PinKeyboardFocusedTab(browser_);
778 break;
779 case IDC_GROUP_TARGET_TAB:
780 GroupKeyboardFocusedTab(browser_);
781 break;
782 case IDC_DUPLICATE_TARGET_TAB:
783 DuplicateKeyboardFocusedTab(browser_);
784 break;
785 // Hosted App commands
786 case IDC_COPY_URL:
787 CopyURL(browser_);
788 break;
789 case IDC_OPEN_IN_CHROME:
790 OpenInChrome(browser_);
791 break;
792 case IDC_SITE_SETTINGS:
793 ShowSiteSettings(
794 browser_,
795 browser_->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
796 break;
797 case IDC_WEB_APP_MENU_APP_INFO: {
798 content::WebContents* const web_contents =
799 browser_->tab_strip_model()->GetActiveWebContents();
800 if (web_contents) {
801 ShowPageInfoDialog(web_contents,
802 base::BindOnce(&AppInfoDialogClosedCallback,
803 base::Unretained(web_contents)),
804 bubble_anchor_util::kAppMenuButton);
805 }
806 break;
807 }
808 default:
809 LOG(WARNING) << "Received Unimplemented Command: " << id;
810 break;
811 }
812
813 return true;
814 }
815
AddCommandObserver(int id,CommandObserver * observer)816 void BrowserCommandController::AddCommandObserver(int id,
817 CommandObserver* observer) {
818 command_updater_.AddCommandObserver(id, observer);
819 }
820
RemoveCommandObserver(int id,CommandObserver * observer)821 void BrowserCommandController::RemoveCommandObserver(
822 int id,
823 CommandObserver* observer) {
824 command_updater_.RemoveCommandObserver(id, observer);
825 }
826
RemoveCommandObserver(CommandObserver * observer)827 void BrowserCommandController::RemoveCommandObserver(
828 CommandObserver* observer) {
829 command_updater_.RemoveCommandObserver(observer);
830 }
831
UpdateCommandEnabled(int id,bool state)832 bool BrowserCommandController::UpdateCommandEnabled(int id, bool state) {
833 if (is_locked_fullscreen_)
834 return false;
835
836 return command_updater_.UpdateCommandEnabled(id, state);
837 }
838
839 ////////////////////////////////////////////////////////////////////////////////
840 // BrowserCommandController, SigninPrefObserver implementation:
841
OnSigninAllowedPrefChange()842 void BrowserCommandController::OnSigninAllowedPrefChange() {
843 // For unit tests, we don't have a window.
844 if (!window())
845 return;
846 UpdateShowSyncState(IsShowingMainUI());
847 }
848
849 // BrowserCommandController, TabStripModelObserver implementation:
850
OnTabStripModelChanged(TabStripModel * tab_strip_model,const TabStripModelChange & change,const TabStripSelectionChange & selection)851 void BrowserCommandController::OnTabStripModelChanged(
852 TabStripModel* tab_strip_model,
853 const TabStripModelChange& change,
854 const TabStripSelectionChange& selection) {
855 std::vector<content::WebContents*> new_contents;
856 std::vector<content::WebContents*> old_contents;
857
858 switch (change.type()) {
859 case TabStripModelChange::kInserted:
860 for (const auto& contents : change.GetInsert()->contents)
861 new_contents.push_back(contents.contents);
862 break;
863 case TabStripModelChange::kReplaced: {
864 auto* replace = change.GetReplace();
865 new_contents.push_back(replace->new_contents);
866 old_contents.push_back(replace->old_contents);
867 break;
868 }
869 case TabStripModelChange::kRemoved:
870 for (const auto& contents : change.GetRemove()->contents)
871 old_contents.push_back(contents.contents);
872 break;
873 default:
874 break;
875 }
876 }
877
TabBlockedStateChanged(content::WebContents * contents,int index)878 void BrowserCommandController::TabBlockedStateChanged(
879 content::WebContents* contents,
880 int index) {
881 PrintingStateChanged();
882 FullscreenStateChanged();
883 UpdateCommandsForFind();
884 UpdateCommandsForMediaRouter();
885 }
886
887 ////////////////////////////////////////////////////////////////////////////////
888 // BrowserCommandController, TabRestoreServiceObserver implementation:
889
TabRestoreServiceChanged(sessions::TabRestoreService * service)890 void BrowserCommandController::TabRestoreServiceChanged(
891 sessions::TabRestoreService* service) {
892 UpdateTabRestoreCommandState();
893 }
894
TabRestoreServiceDestroyed(sessions::TabRestoreService * service)895 void BrowserCommandController::TabRestoreServiceDestroyed(
896 sessions::TabRestoreService* service) {
897 service->RemoveObserver(this);
898 }
899
TabRestoreServiceLoaded(sessions::TabRestoreService * service)900 void BrowserCommandController::TabRestoreServiceLoaded(
901 sessions::TabRestoreService* service) {
902 UpdateTabRestoreCommandState();
903 }
904
905 ////////////////////////////////////////////////////////////////////////////////
906 // BrowserCommandController, private:
907
IsShowingMainUI()908 bool BrowserCommandController::IsShowingMainUI() {
909 return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
910 }
911
IsShowingLocationBar()912 bool BrowserCommandController::IsShowingLocationBar() {
913 return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
914 }
915
InitCommandState()916 void BrowserCommandController::InitCommandState() {
917 // All browser commands whose state isn't set automagically some other way
918 // (like Back & Forward with initial page load) must have their state
919 // initialized here, otherwise they will be forever disabled.
920
921 if (is_locked_fullscreen_)
922 return;
923
924 // Navigation commands
925 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
926 command_updater_.UpdateCommandEnabled(IDC_RELOAD_BYPASSING_CACHE, true);
927 command_updater_.UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE, true);
928
929 // Window management commands
930 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
931 command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
932 command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
933 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
934 UpdateTabRestoreCommandState();
935 command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
936 command_updater_.UpdateCommandEnabled(IDC_DEBUG_FRAME_TOGGLE, true);
937 command_updater_.UpdateCommandEnabled(IDC_NAME_WINDOW, true);
938 #if defined(OS_CHROMEOS)
939 command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true);
940 // The VisitDesktop command is only supported for up to 5 logged in users
941 // because that's the max number of user sessions. If that number is increased
942 // the IDC_VISIT_DESKTOP_OF_LRU_USER_ command ids should be updated as well.
943 // crbug.com/940461
944 static_assert(
945 session_manager::kMaximumNumberOfUserSessions <=
946 IDC_VISIT_DESKTOP_OF_LRU_USER_LAST -
947 IDC_VISIT_DESKTOP_OF_LRU_USER_NEXT + 2,
948 "The max number of user sessions exceeds the number of users supported.");
949 command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_2, true);
950 command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_3, true);
951 command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_4, true);
952 command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_5, true);
953 #endif
954 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS)
955 command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true);
956 command_updater_.UpdateCommandEnabled(IDC_MAXIMIZE_WINDOW, true);
957 command_updater_.UpdateCommandEnabled(IDC_RESTORE_WINDOW, true);
958 bool use_system_title_bar = true;
959 #if defined(USE_OZONE)
960 if (features::IsUsingOzonePlatform()) {
961 use_system_title_bar = ui::OzonePlatform::GetInstance()
962 ->GetPlatformProperties()
963 .use_system_title_bar;
964 }
965 #endif
966 command_updater_.UpdateCommandEnabled(IDC_USE_SYSTEM_TITLE_BAR,
967 use_system_title_bar);
968 #endif
969 command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_PWA_WINDOW, true);
970
971 // Page-related commands
972 command_updater_.UpdateCommandEnabled(IDC_MANAGE_PASSWORDS_FOR_PAGE, true);
973
974 // Zoom
975 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
976 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
977 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, false);
978 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
979
980 // Show various bits of UI
981 DCHECK(!profile()->IsSystemProfile())
982 << "Ought to never have browser for the system profile.";
983 const bool normal_window = browser_->is_type_normal();
984 UpdateOpenFileState(&command_updater_);
985 UpdateCommandsForDevTools();
986 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, CanOpenTaskManager());
987 command_updater_.UpdateCommandEnabled(
988 IDC_SHOW_HISTORY,
989 (!profile()->IsGuestSession() && !profile()->IsSystemProfile()));
990 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
991 command_updater_.UpdateCommandEnabled(IDC_HELP_MENU, true);
992 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_KEYBOARD, true);
993 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_MENU, true);
994 command_updater_.UpdateCommandEnabled(IDC_SHOW_BETA_FORUM, true);
995 command_updater_.UpdateCommandEnabled(
996 IDC_BOOKMARKS_MENU,
997 (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
998 !profile()->IsEphemeralGuestProfile()));
999 command_updater_.UpdateCommandEnabled(
1000 IDC_RECENT_TABS_MENU,
1001 (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
1002 !profile()->IsIncognitoProfile()));
1003 command_updater_.UpdateCommandEnabled(
1004 IDC_CLEAR_BROWSING_DATA,
1005 (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
1006 !profile()->IsIncognitoProfile()));
1007 #if defined(OS_CHROMEOS)
1008 command_updater_.UpdateCommandEnabled(IDC_TAKE_SCREENSHOT, true);
1009 // Chrome OS uses the system tray menu to handle multi-profiles. Avatar menu
1010 // is only required in incognito mode.
1011 if (profile()->IsIncognitoProfile())
1012 command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, true);
1013 #else
1014 if (normal_window)
1015 command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, true);
1016 #endif
1017 command_updater_.UpdateCommandEnabled(
1018 IDC_SHOW_SAVE_LOCAL_CARD_SIGN_IN_PROMO_IF_APPLICABLE, true);
1019 command_updater_.UpdateCommandEnabled(IDC_CLOSE_SIGN_IN_PROMO, true);
1020 command_updater_.UpdateCommandEnabled(IDC_CARET_BROWSING_TOGGLE, true);
1021 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_COMMANDER,
1022 commander::IsEnabled());
1023 UpdateShowSyncState(true);
1024
1025 // Navigation commands
1026 command_updater_.UpdateCommandEnabled(
1027 IDC_HOME, normal_window || browser_->deprecated_is_app());
1028
1029 const bool is_web_app_or_custom_tab =
1030 #if defined(OS_CHROMEOS)
1031 browser_->is_type_custom_tab() ||
1032 #endif
1033 web_app::AppBrowserController::IsForWebAppBrowser(browser_);
1034 // Hosted app browser commands.
1035 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, is_web_app_or_custom_tab);
1036 command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_CHROME,
1037 is_web_app_or_custom_tab);
1038 command_updater_.UpdateCommandEnabled(IDC_SITE_SETTINGS,
1039 is_web_app_or_custom_tab);
1040 command_updater_.UpdateCommandEnabled(IDC_WEB_APP_MENU_APP_INFO,
1041 is_web_app_or_custom_tab);
1042
1043 // Tab management commands
1044 const bool supports_tabs =
1045 browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
1046 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, supports_tabs);
1047 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, supports_tabs);
1048 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, supports_tabs);
1049 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, supports_tabs);
1050 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, supports_tabs);
1051 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, supports_tabs);
1052 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, supports_tabs);
1053 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, supports_tabs);
1054 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, supports_tabs);
1055 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, supports_tabs);
1056 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, supports_tabs);
1057 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, supports_tabs);
1058 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, supports_tabs);
1059
1060 // These are always enabled; the menu determines their menu item visibility.
1061 command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
1062
1063 // Distill current page.
1064 command_updater_.UpdateCommandEnabled(IDC_DISTILL_PAGE,
1065 dom_distiller::IsDomDistillerEnabled());
1066
1067 command_updater_.UpdateCommandEnabled(IDC_WINDOW_MUTE_SITE, normal_window);
1068 command_updater_.UpdateCommandEnabled(IDC_WINDOW_PIN_TAB, normal_window);
1069 command_updater_.UpdateCommandEnabled(IDC_WINDOW_GROUP_TAB, normal_window);
1070 command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_TABS_TO_RIGHT,
1071 normal_window);
1072 command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_OTHER_TABS,
1073 normal_window);
1074
1075 const bool enable_tab_search_commands =
1076 base::FeatureList::IsEnabled(features::kTabSearch) &&
1077 browser_->is_type_normal();
1078 command_updater_.UpdateCommandEnabled(IDC_TAB_SEARCH,
1079 enable_tab_search_commands);
1080 command_updater_.UpdateCommandEnabled(IDC_TAB_SEARCH_CLOSE,
1081 enable_tab_search_commands);
1082
1083 // Initialize other commands whose state changes based on various conditions.
1084 UpdateCommandsForFullscreenMode();
1085 UpdateCommandsForContentRestrictionState();
1086 UpdateCommandsForBookmarkEditing();
1087 UpdateCommandsForIncognitoAvailability();
1088 UpdateCommandsForTabKeyboardFocus(GetKeyboardFocusedTabIndex(browser_));
1089 UpdateCommandsForWebContentsFocus();
1090 }
1091
1092 // static
UpdateSharedCommandsForIncognitoAvailability(CommandUpdater * command_updater,Profile * profile)1093 void BrowserCommandController::UpdateSharedCommandsForIncognitoAvailability(
1094 CommandUpdater* command_updater,
1095 Profile* profile) {
1096 IncognitoModePrefs::Availability incognito_availability =
1097 IncognitoModePrefs::GetAvailability(profile->GetPrefs());
1098 command_updater->UpdateCommandEnabled(
1099 IDC_NEW_WINDOW, incognito_availability != IncognitoModePrefs::FORCED);
1100 command_updater->UpdateCommandEnabled(
1101 IDC_NEW_INCOGNITO_WINDOW,
1102 incognito_availability != IncognitoModePrefs::DISABLED &&
1103 !profile->IsGuestSession() && !profile->IsEphemeralGuestProfile());
1104
1105 const bool forced_incognito =
1106 incognito_availability == IncognitoModePrefs::FORCED;
1107 const bool is_guest =
1108 profile->IsGuestSession() || profile->IsEphemeralGuestProfile();
1109
1110 command_updater->UpdateCommandEnabled(
1111 IDC_SHOW_BOOKMARK_MANAGER,
1112 browser_defaults::bookmarks_enabled && !forced_incognito && !is_guest);
1113 extensions::ExtensionService* extension_service =
1114 extensions::ExtensionSystem::Get(profile)->extension_service();
1115 const bool enable_extensions =
1116 extension_service && extension_service->extensions_enabled();
1117
1118 command_updater->UpdateCommandEnabled(IDC_SHOW_FULL_URLS, true);
1119
1120 // Bookmark manager and settings page/subpages are forced to open in normal
1121 // mode. For this reason we disable these commands when incognito is forced.
1122 command_updater->UpdateCommandEnabled(
1123 IDC_MANAGE_EXTENSIONS,
1124 enable_extensions && !forced_incognito && !is_guest);
1125
1126 command_updater->UpdateCommandEnabled(IDC_IMPORT_SETTINGS,
1127 !forced_incognito && !is_guest);
1128 command_updater->UpdateCommandEnabled(IDC_OPTIONS,
1129 !forced_incognito || is_guest);
1130 command_updater->UpdateCommandEnabled(IDC_SHOW_SIGNIN,
1131 !forced_incognito && !is_guest);
1132 }
1133
UpdateCommandsForIncognitoAvailability()1134 void BrowserCommandController::UpdateCommandsForIncognitoAvailability() {
1135 if (is_locked_fullscreen_)
1136 return;
1137
1138 UpdateSharedCommandsForIncognitoAvailability(&command_updater_, profile());
1139
1140 if (!IsShowingMainUI()) {
1141 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, false);
1142 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, false);
1143 }
1144 }
1145
UpdateCommandsForTabState()1146 void BrowserCommandController::UpdateCommandsForTabState() {
1147 if (is_locked_fullscreen_)
1148 return;
1149
1150 WebContents* current_web_contents =
1151 browser_->tab_strip_model()->GetActiveWebContents();
1152 if (!current_web_contents) // May be NULL during tab restore.
1153 return;
1154
1155 // Navigation commands
1156 command_updater_.UpdateCommandEnabled(IDC_BACK, CanGoBack(browser_));
1157 command_updater_.UpdateCommandEnabled(IDC_FORWARD, CanGoForward(browser_));
1158 command_updater_.UpdateCommandEnabled(IDC_RELOAD, CanReload(browser_));
1159 command_updater_.UpdateCommandEnabled(IDC_RELOAD_BYPASSING_CACHE,
1160 CanReload(browser_));
1161 command_updater_.UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE,
1162 CanReload(browser_));
1163
1164 // Window management commands
1165 command_updater_.UpdateCommandEnabled(
1166 IDC_DUPLICATE_TAB,
1167 !browser_->deprecated_is_app() && CanDuplicateTab(browser_));
1168 command_updater_.UpdateCommandEnabled(IDC_WINDOW_MUTE_SITE,
1169 !browser_->deprecated_is_app());
1170 command_updater_.UpdateCommandEnabled(IDC_WINDOW_PIN_TAB,
1171 !browser_->deprecated_is_app());
1172 command_updater_.UpdateCommandEnabled(IDC_WINDOW_GROUP_TAB,
1173 !browser_->deprecated_is_app());
1174 command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_TABS_TO_RIGHT,
1175 CanCloseTabsToRight(browser_));
1176 command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_OTHER_TABS,
1177 CanCloseOtherTabs(browser_));
1178 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_TO_NEW_WINDOW,
1179 CanMoveActiveTabToNewWindow(browser_));
1180
1181 // Page-related commands
1182 window()->SetStarredState(
1183 BookmarkTabHelper::FromWebContents(current_web_contents)->is_starred());
1184 window()->ZoomChangedForActiveTab(false);
1185 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
1186 CanViewSource(browser_));
1187 if (browser_->is_type_devtools())
1188 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, false);
1189
1190 bool can_create_web_app = web_app::CanCreateWebApp(browser_);
1191 command_updater_.UpdateCommandEnabled(IDC_INSTALL_PWA, can_create_web_app);
1192 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT,
1193 can_create_web_app);
1194 // Note that additional logic in AppMenuModel::Build() controls the presence
1195 // of this command.
1196 command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_PWA_WINDOW,
1197 web_app::CanPopOutWebApp(profile()));
1198
1199 command_updater_.UpdateCommandEnabled(
1200 IDC_TOGGLE_REQUEST_TABLET_SITE,
1201 CanRequestTabletSite(current_web_contents));
1202
1203 UpdateCommandsForContentRestrictionState();
1204 UpdateCommandsForBookmarkEditing();
1205 UpdateCommandsForFind();
1206 UpdateCommandsForMediaRouter();
1207 // Update the zoom commands when an active tab is selected.
1208 UpdateCommandsForZoomState();
1209 UpdateCommandsForTabKeyboardFocus(GetKeyboardFocusedTabIndex(browser_));
1210 }
1211
UpdateCommandsForZoomState()1212 void BrowserCommandController::UpdateCommandsForZoomState() {
1213 WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
1214 if (!contents)
1215 return;
1216 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, CanZoomIn(contents));
1217 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL,
1218 CanResetZoom(contents));
1219 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, CanZoomOut(contents));
1220 }
1221
UpdateCommandsForContentRestrictionState()1222 void BrowserCommandController::UpdateCommandsForContentRestrictionState() {
1223 int restrictions = GetContentRestrictions(browser_);
1224
1225 command_updater_.UpdateCommandEnabled(
1226 IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY));
1227 command_updater_.UpdateCommandEnabled(
1228 IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT));
1229 command_updater_.UpdateCommandEnabled(
1230 IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE));
1231 UpdateSaveAsState();
1232 UpdatePrintingState();
1233 }
1234
UpdateCommandsForDevTools()1235 void BrowserCommandController::UpdateCommandsForDevTools() {
1236 if (is_locked_fullscreen_)
1237 return;
1238
1239 bool dev_tools_enabled = DevToolsWindow::AllowDevToolsFor(
1240 profile(), browser_->tab_strip_model()->GetActiveWebContents());
1241 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, dev_tools_enabled);
1242 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
1243 dev_tools_enabled);
1244 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_DEVICES,
1245 dev_tools_enabled);
1246 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
1247 dev_tools_enabled);
1248 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_TOGGLE,
1249 dev_tools_enabled);
1250 #if defined(OS_MAC)
1251 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_JAVASCRIPT_APPLE_EVENTS,
1252 dev_tools_enabled);
1253 #endif
1254 }
1255
UpdateCommandsForBookmarkEditing()1256 void BrowserCommandController::UpdateCommandsForBookmarkEditing() {
1257 if (is_locked_fullscreen_)
1258 return;
1259
1260 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_THIS_TAB,
1261 CanBookmarkCurrentTab(browser_));
1262 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
1263 CanBookmarkAllTabs(browser_));
1264 #if defined(OS_WIN)
1265 command_updater_.UpdateCommandEnabled(IDC_PIN_TO_START_SCREEN, true);
1266 #endif
1267 }
1268
UpdateCommandsForBookmarkBar()1269 void BrowserCommandController::UpdateCommandsForBookmarkBar() {
1270 if (is_locked_fullscreen_)
1271 return;
1272
1273 command_updater_.UpdateCommandEnabled(
1274 IDC_SHOW_BOOKMARK_BAR, browser_defaults::bookmarks_enabled &&
1275 !profile()->IsGuestSession() &&
1276 !profile()->IsEphemeralGuestProfile() &&
1277 !profile()->IsSystemProfile() &&
1278 !profile()->GetPrefs()->IsManagedPreference(
1279 bookmarks::prefs::kShowBookmarkBar) &&
1280 IsShowingMainUI());
1281 }
1282
UpdateCommandsForFileSelectionDialogs()1283 void BrowserCommandController::UpdateCommandsForFileSelectionDialogs() {
1284 if (is_locked_fullscreen_)
1285 return;
1286
1287 UpdateSaveAsState();
1288 UpdateOpenFileState(&command_updater_);
1289 }
1290
UpdateCommandsForFullscreenMode()1291 void BrowserCommandController::UpdateCommandsForFullscreenMode() {
1292 if (is_locked_fullscreen_)
1293 return;
1294
1295 const bool is_fullscreen = window() && window()->IsFullscreen();
1296 const bool show_main_ui = IsShowingMainUI();
1297 const bool show_location_bar = IsShowingLocationBar();
1298
1299 const bool main_not_fullscreen = show_main_ui && !is_fullscreen;
1300
1301 // Navigation commands
1302 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
1303
1304 // Window management commands
1305 command_updater_.UpdateCommandEnabled(
1306 IDC_SHOW_AS_TAB, !browser_->is_type_normal() && !is_fullscreen);
1307
1308 // Focus various bits of UI
1309 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
1310 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_location_bar);
1311 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
1312 command_updater_.UpdateCommandEnabled(IDC_FOCUS_MENU_BAR,
1313 main_not_fullscreen);
1314 command_updater_.UpdateCommandEnabled(IDC_FOCUS_NEXT_PANE,
1315 main_not_fullscreen);
1316 command_updater_.UpdateCommandEnabled(IDC_FOCUS_PREVIOUS_PANE,
1317 main_not_fullscreen);
1318 command_updater_.UpdateCommandEnabled(IDC_FOCUS_BOOKMARKS,
1319 main_not_fullscreen);
1320 command_updater_.UpdateCommandEnabled(
1321 IDC_FOCUS_INACTIVE_POPUP_FOR_ACCESSIBILITY, main_not_fullscreen);
1322
1323 // Show various bits of UI
1324 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
1325 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
1326 command_updater_.UpdateCommandEnabled(
1327 IDC_FEEDBACK, show_main_ui || browser_->is_type_devtools());
1328 #endif
1329 UpdateShowSyncState(show_main_ui);
1330
1331 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
1332 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
1333 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
1334 command_updater_.UpdateCommandEnabled(IDC_QRCODE_GENERATOR, show_main_ui);
1335 command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
1336 command_updater_.UpdateCommandEnabled(IDC_SEND_TAB_TO_SELF, show_main_ui);
1337 command_updater_.UpdateCommandEnabled(IDC_SEND_TAB_TO_SELF_SINGLE_TARGET,
1338 show_main_ui);
1339 command_updater_.UpdateCommandEnabled(IDC_SHOW_MANAGEMENT_PAGE, true);
1340
1341 if (base::debug::IsProfilingSupported())
1342 command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
1343
1344 #if !defined(OS_MAC)
1345 // Disable toggling into fullscreen mode if disallowed by pref.
1346 const bool fullscreen_enabled =
1347 is_fullscreen ||
1348 profile()->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed);
1349 #else
1350 const bool fullscreen_enabled = true;
1351 #endif
1352
1353 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, fullscreen_enabled);
1354 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_FULLSCREEN_TOOLBAR,
1355 fullscreen_enabled);
1356
1357 UpdateCommandsForBookmarkBar();
1358 UpdateCommandsForIncognitoAvailability();
1359 UpdateCommandsForHostedAppAvailability();
1360 }
1361
UpdateCommandsForHostedAppAvailability()1362 void BrowserCommandController::UpdateCommandsForHostedAppAvailability() {
1363 bool has_toolbar =
1364 browser_->is_type_normal() ||
1365 web_app::AppBrowserController::IsForWebAppBrowser(browser_);
1366 if (window() && window()->ShouldHideUIForFullscreen())
1367 has_toolbar = false;
1368 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, has_toolbar);
1369 command_updater_.UpdateCommandEnabled(IDC_FOCUS_NEXT_PANE, has_toolbar);
1370 command_updater_.UpdateCommandEnabled(IDC_FOCUS_PREVIOUS_PANE, has_toolbar);
1371 command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, has_toolbar);
1372 }
1373
1374 #if defined(OS_CHROMEOS)
1375 namespace {
1376
1377 #if DCHECK_IS_ON()
1378 // Makes sure that all commands that are not allowlisted are disabled. DCHECKs
1379 // otherwise. Compiled only in debug mode.
NonAllowlistedCommandsAreDisabled(CommandUpdaterImpl * command_updater)1380 void NonAllowlistedCommandsAreDisabled(CommandUpdaterImpl* command_updater) {
1381 constexpr int kAllowlistedIds[] = {IDC_CUT, IDC_COPY, IDC_PASTE};
1382
1383 // Go through all the command ids, skip the allowlisted ones.
1384 for (int id : command_updater->GetAllIds()) {
1385 if (base::Contains(kAllowlistedIds, id)) {
1386 continue;
1387 }
1388 DCHECK(!command_updater->IsCommandEnabled(id));
1389 }
1390 }
1391 #endif
1392
1393 } // namespace
1394
UpdateCommandsForLockedFullscreenMode()1395 void BrowserCommandController::UpdateCommandsForLockedFullscreenMode() {
1396 bool is_locked_fullscreen =
1397 platform_util::IsBrowserLockedFullscreen(browser_);
1398 // Sanity check to make sure this function is called only on state change.
1399 DCHECK_NE(is_locked_fullscreen, is_locked_fullscreen_);
1400 if (is_locked_fullscreen == is_locked_fullscreen_)
1401 return;
1402 is_locked_fullscreen_ = is_locked_fullscreen;
1403
1404 if (is_locked_fullscreen_) {
1405 command_updater_.DisableAllCommands();
1406 // Update the state of allowlisted commands:
1407 // IDC_CUT/IDC_COPY/IDC_PASTE,
1408 UpdateCommandsForContentRestrictionState();
1409 // TODO(crbug.com/904637): Re-enable Find and Zoom in locked fullscreen.
1410 // All other commands will be disabled (there is an early return in their
1411 // corresponding UpdateCommandsFor* functions).
1412 #if DCHECK_IS_ON()
1413 NonAllowlistedCommandsAreDisabled(&command_updater_);
1414 #endif
1415 } else {
1416 // Do an init call to re-initialize command state after the
1417 // DisableAllCommands.
1418 InitCommandState();
1419 }
1420 }
1421 #endif
1422
UpdatePrintingState()1423 void BrowserCommandController::UpdatePrintingState() {
1424 if (is_locked_fullscreen_)
1425 return;
1426
1427 bool print_enabled = CanPrint(browser_);
1428 command_updater_.UpdateCommandEnabled(IDC_PRINT, print_enabled);
1429 #if BUILDFLAG(ENABLE_PRINTING)
1430 command_updater_.UpdateCommandEnabled(IDC_BASIC_PRINT,
1431 CanBasicPrint(browser_));
1432 #endif
1433 }
1434
UpdateSaveAsState()1435 void BrowserCommandController::UpdateSaveAsState() {
1436 if (is_locked_fullscreen_)
1437 return;
1438
1439 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, CanSavePage(browser_));
1440 }
1441
UpdateShowSyncState(bool show_main_ui)1442 void BrowserCommandController::UpdateShowSyncState(bool show_main_ui) {
1443 if (is_locked_fullscreen_)
1444 return;
1445
1446 command_updater_.UpdateCommandEnabled(
1447 IDC_SHOW_SIGNIN, show_main_ui && pref_signin_allowed_.GetValue());
1448 }
1449
1450 // static
UpdateOpenFileState(CommandUpdater * command_updater)1451 void BrowserCommandController::UpdateOpenFileState(
1452 CommandUpdater* command_updater) {
1453 bool enabled = true;
1454 PrefService* local_state = g_browser_process->local_state();
1455 if (local_state)
1456 enabled = local_state->GetBoolean(prefs::kAllowFileSelectionDialogs);
1457
1458 command_updater->UpdateCommandEnabled(IDC_OPEN_FILE, enabled);
1459 }
1460
UpdateReloadStopState(bool is_loading,bool force)1461 void BrowserCommandController::UpdateReloadStopState(bool is_loading,
1462 bool force) {
1463 if (is_locked_fullscreen_)
1464 return;
1465
1466 window()->UpdateReloadStopState(is_loading, force);
1467 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
1468 UpdateCloseFindOrStop();
1469 }
1470
UpdateTabRestoreCommandState()1471 void BrowserCommandController::UpdateTabRestoreCommandState() {
1472 if (is_locked_fullscreen_)
1473 return;
1474
1475 sessions::TabRestoreService* tab_restore_service =
1476 TabRestoreServiceFactory::GetForProfile(profile());
1477 // The command is enabled if the service hasn't loaded yet to trigger loading.
1478 // The command is updated once the load completes.
1479 command_updater_.UpdateCommandEnabled(
1480 IDC_RESTORE_TAB,
1481 tab_restore_service && (!tab_restore_service->IsLoaded() ||
1482 !tab_restore_service->entries().empty()));
1483 }
1484
UpdateCommandsForFind()1485 void BrowserCommandController::UpdateCommandsForFind() {
1486 TabStripModel* model = browser_->tab_strip_model();
1487 bool enabled = !model->IsTabBlocked(model->active_index()) &&
1488 !browser_->is_type_devtools();
1489
1490 command_updater_.UpdateCommandEnabled(IDC_FIND, enabled);
1491 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, enabled);
1492 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, enabled);
1493 }
1494
UpdateCloseFindOrStop()1495 void BrowserCommandController::UpdateCloseFindOrStop() {
1496 bool enabled = CanCloseFind(browser_) || IsCommandEnabled(IDC_STOP);
1497 command_updater_.UpdateCommandEnabled(IDC_CLOSE_FIND_OR_STOP, enabled);
1498 }
1499
UpdateCommandsForMediaRouter()1500 void BrowserCommandController::UpdateCommandsForMediaRouter() {
1501 if (is_locked_fullscreen_)
1502 return;
1503
1504 command_updater_.UpdateCommandEnabled(IDC_ROUTE_MEDIA,
1505 CanRouteMedia(browser_));
1506 }
1507
UpdateCommandsForTabKeyboardFocus(base::Optional<int> target_index)1508 void BrowserCommandController::UpdateCommandsForTabKeyboardFocus(
1509 base::Optional<int> target_index) {
1510 command_updater_.UpdateCommandEnabled(
1511 IDC_DUPLICATE_TARGET_TAB, !browser_->deprecated_is_app() &&
1512 target_index.has_value() &&
1513 CanDuplicateTabAt(browser_, *target_index));
1514 const bool normal_window = browser_->is_type_normal();
1515 command_updater_.UpdateCommandEnabled(
1516 IDC_MUTE_TARGET_SITE, normal_window && target_index.has_value());
1517 command_updater_.UpdateCommandEnabled(
1518 IDC_PIN_TARGET_TAB, normal_window && target_index.has_value());
1519 command_updater_.UpdateCommandEnabled(
1520 IDC_GROUP_TARGET_TAB, normal_window && target_index.has_value());
1521 }
1522
UpdateCommandsForWebContentsFocus()1523 void BrowserCommandController::UpdateCommandsForWebContentsFocus() {
1524 #if defined(OS_MAC)
1525 // On Mac, toggling caret browsing changes whether it's enabled or not
1526 // based on web contents focus.
1527 command_updater_.UpdateCommandEnabled(IDC_CARET_BROWSING_TOGGLE,
1528 CanToggleCaretBrowsing(browser_));
1529 #endif // defined(OS_MAC)
1530 }
1531
window()1532 BrowserWindow* BrowserCommandController::window() {
1533 return browser_->window();
1534 }
1535
profile()1536 Profile* BrowserCommandController::profile() {
1537 return browser_->profile();
1538 }
1539
1540 } // namespace chrome
1541