| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "chrome/browser/ui/cocoa/history_menu_cocoa_controller.h" |
| |
| #import "base/mac/foundation_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/metrics/user_metrics.h" |
| #include "chrome/app/chrome_command_ids.h" // IDC_HISTORY_MENU |
| #import "chrome/browser/app_controller_mac.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/browser_live_tab_context.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_navigator_params.h" |
| #include "components/history/core/browser/history_service.h" |
| #include "components/history/core/browser/history_types.h" |
| #include "components/sessions/core/session_id.h" |
| #include "components/sessions/core/tab_restore_service.h" |
| #import "ui/base/cocoa/cocoa_base_utils.h" |
| #include "ui/base/window_open_disposition.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| using content::OpenURLParams; |
| using content::Referrer; |
| |
| namespace { |
| |
| // TODO(crbug.com/1334721): Single-tab windows get restored as tabs instead of |
| // windows, which is confusing. |
| // |
| // NB: Takes |node| by value, because the HistoryMenuBridge could be destroyed |
| // before RunInSafeProfileHelper finishes. |
| void OpenURLForItem(HistoryMenuBridge::HistoryItem node, |
| WindowOpenDisposition disposition, |
| Profile* profile) { |
| if (!profile) |
| return; // Failed to load profile, ignore. |
| // If this item can be restored using TabRestoreService, do so. Otherwise, |
| // just load the URL. |
| if (node.session_id.is_valid()) { |
| app_controller_mac::TabRestorer::RestoreByID(profile, node.session_id); |
| } else { |
| DCHECK(node.url.is_valid()); |
| Profile* target_profile = profile; |
| |
| // Allow a history menu item to open in an active incognito window. |
| // Specifically, if the active window has the same root profile as the |
| // bridge, target the active profile. Without this, history menu items open |
| // in the nearest non-incognito window, or create one. |
| if (auto* active_browser = chrome::FindBrowserWithActiveWindow()) { |
| if (active_browser->profile()->GetOriginalProfile() == target_profile) |
| target_profile = active_browser->profile(); |
| } |
| |
| NavigateParams params(target_profile, node.url, |
| ui::PAGE_TRANSITION_AUTO_BOOKMARK); |
| params.disposition = disposition; |
| Navigate(¶ms); |
| } |
| } |
| |
| } // namespace |
| |
| @implementation HistoryMenuCocoaController { |
| raw_ptr<HistoryMenuBridge, DanglingAcrossTasks> _bridge; // weak; owns us |
| } |
| |
| - (instancetype)initWithBridge:(HistoryMenuBridge*)bridge { |
| if ((self = [super init])) { |
| _bridge = bridge; |
| DCHECK(_bridge); |
| } |
| return self; |
| } |
| |
| - (BOOL)validateMenuItem:(NSMenuItem*)menuItem { |
| return ![AppController.sharedController keyWindowIsModal]; |
| } |
| |
| // Open the URL of the given history item in the current tab. |
| - (void)openURLForItem:(const HistoryMenuBridge::HistoryItem*)node { |
| WindowOpenDisposition disposition = |
| ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); |
| if (Profile* profile = _bridge->profile()) { |
| OpenURLForItem(*node, disposition, profile); |
| } else { |
| // Both HistoryMenuBridge and HistoryMenuCocoaController could get destroyed |
| // before RunInSafeProfileHelper finishes. The callback needs to be |
| // self-contained. |
| app_controller_mac::RunInProfileSafely( |
| _bridge->profile_dir(), |
| base::BindOnce(&OpenURLForItem, *node, disposition), |
| app_controller_mac::kIgnoreOnFailure); |
| } |
| } |
| |
| - (IBAction)openHistoryMenuItem:(id)sender { |
| const HistoryMenuBridge::HistoryItem* item = |
| _bridge->HistoryItemForMenuItem(sender); |
| |
| if ([sender tag] == HistoryMenuBridge::kRecentlyClosed) { |
| base::RecordAction( |
| base::UserMetricsAction("TopMenu_History_RecentlyClosed")); |
| } else if ([sender tag] == HistoryMenuBridge::kVisited) { |
| base::RecordAction( |
| base::UserMetricsAction("TopMenu_History_RecentlyVisited")); |
| } |
| |
| [self openURLForItem:item]; |
| } |
| |
| // NSMenuDelegate: |
| |
| - (void)menuWillOpen:(NSMenu*)menu { |
| _bridge->SetIsMenuOpen(true); |
| } |
| |
| - (void)menuDidClose:(NSMenu*)menu { |
| _bridge->SetIsMenuOpen(false); |
| } |
| |
| @end // HistoryMenuCocoaController |