1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
|
// 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.
#ifndef CHROME_BROWSER_APP_CONTROLLER_MAC_H_
#define CHROME_BROWSER_APP_CONTROLLER_MAC_H_
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/profiles/profile.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/tab_restore_service.h"
#include "components/sessions/core/tab_restore_service_observer.h"
#if defined(__OBJC__)
#import <AuthenticationServices/AuthenticationServices.h>
#import <Cocoa/Cocoa.h>
#include <memory>
#include <vector>
#include "base/files/file_path.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "components/prefs/pref_change_registrar.h"
class BookmarkMenuBridge;
class GURL;
class HistoryMenuBridge;
class Profile;
class TabMenuBridge;
namespace ui {
class ColorProvider;
} // namespace ui
// The application controller object, created by loading the MainMenu nib.
// This handles things like responding to menus when there are no windows
// open, etc and acts as the NSApplication delegate.
@interface AppController
: NSObject <NSUserInterfaceValidations,
NSMenuDelegate,
NSApplicationDelegate,
ASWebAuthenticationSessionWebBrowserSessionHandling>
// The app-wide singleton AppController. Guaranteed to be the delegate of NSApp
// inside of Chromium (not inside of app shims; see AppShimDelegate). Guaranteed
// to not be nil.
@property(readonly, nonatomic, class) AppController* sharedController;
@property(readonly, nonatomic) BOOL startupComplete;
@property(readonly, nonatomic) Profile* lastProfileIfLoaded;
// DEPRECATED: use lastProfileIfLoaded instead.
// TODO(crbug.com/40054768): May be blocking, migrate all callers to
// |-lastProfileIfLoaded|.
@property(readonly, nonatomic) Profile* lastProfile;
// Do not create new instances of AppController; use the `sharedController`
// property so that the invariants of there always being exactly one
// AppController and that that instance is the NSApp delegate always hold true.
- (instancetype)init NS_UNAVAILABLE;
// This method is called very early in application startup after the main menu
// has been created.
- (void)mainMenuCreated;
- (void)didEndMainMessageLoop;
// Try to close all browser windows, and if that succeeds then quit.
- (BOOL)tryToTerminateApplication:(NSApplication*)app;
// Stop trying to terminate the application. That is, prevent the final browser
// window closure from causing the application to quit.
- (void)stopTryingToTerminateApplication:(NSApplication*)app;
// Run the quit confirmation panel and return whether or not to continue
// quitting.
- (BOOL)runConfirmQuitPanel;
// Indicate that the system is powering off or logging out.
- (void)willPowerOff:(NSNotification*)inNotification;
// Returns true if there is a modal window (either window- or application-
// modal) blocking the active browser. Note that tab modal dialogs (HTTP auth
// sheets) will not count as blocking the browser. But things like open/save
// dialogs that are window modal will block the browser.
- (BOOL)keyWindowIsModal;
// Called when the user picks a menu item when there are no key windows, or when
// there is no foreground browser window. Calls through to the browser object to
// execute the command. This assumes that the command is supported and doesn't
// check, otherwise it should have been disabled in the UI in
// |-validateUserInterfaceItem:|.
- (void)commandDispatch:(id)sender;
// Helper function called by -commandDispatch:, to actually execute the command.
// This runs after -commandDispatch: has obtained a pointer to the last Profile
// (which possibly requires an async Profile load).
- (void)executeCommand:(id)sender withProfile:(Profile*)profile;
// Show the preferences window, or bring it to the front if it's already
// visible.
- (IBAction)showPreferences:(id)sender;
- (IBAction)showPreferencesForProfile:(Profile*)profile;
// Redirect in the menu item from the expected target of "File's
// Owner" (NSApplication) for a Branded About Box
- (IBAction)orderFrontStandardAboutPanel:(id)sender;
- (IBAction)orderFrontStandardAboutPanelForProfile:(Profile*)profile;
// Toggles the "Confirm to Quit" preference.
- (IBAction)toggleConfirmToQuit:(id)sender;
// Delegate method to return the dock menu.
- (NSMenu*)applicationDockMenu:(NSApplication*)sender;
// Get the URLs that Launch Services expects the browser to open at startup.
- (const std::vector<GURL>&)startupUrls;
- (BookmarkMenuBridge*)bookmarkMenuBridge;
- (HistoryMenuBridge*)historyMenuBridge;
- (TabMenuBridge*)tabMenuBridge;
// Called when the user has changed browser windows, meaning the backing profile
// may have changed. This can cause a rebuild of the user-data menus. This is a
// no-op if the new profile is the same as the current one. This can be either
// the original or the incognito profile.
- (void)setLastProfile:(Profile*)profile;
// Returns the last active ColorProvider.
- (const ui::ColorProvider&)lastActiveColorProvider;
// This is called when the system wide light or dark mode changes.
- (void)nativeThemeDidChange;
// Certain NSMenuItems [Close Tab and Close Window] have different
// keyEquivalents depending on context. This must be invoked in two locations:
// * In menuNeedsUpdate:, which is called prior to showing the NSMenu.
// * In CommandDispatcher, which independently searches for a matching
// keyEquivalent.
- (void)updateMenuItemKeyEquivalents;
// Returns YES if `window` is a normal, tabbed, non-app browser window.
// Serves as a swizzle point for unit tests to avoid creating Browser
// instances.
- (BOOL)windowHasBrowserTabs:(NSWindow*)window;
// Testing API.
- (void)setCmdWMenuItemForTesting:(NSMenuItem*)menuItem;
- (void)setShiftCmdWMenuItemForTesting:(NSMenuItem*)menuItem;
// As of macOS Ventura, the browser test harness can no longer make Chrome the
// active app. This can cause mainWindow and related to return nil. For cases
// where having the correct mainWindow is important, set it here.
- (void)setMainWindowForTesting:(NSWindow*)window;
- (void)setLastProfileForTesting:(Profile*)profile;
@end
#endif // __OBJC__
// Functions that may be accessed from non-Objective-C C/C++ code.
namespace app_controller_mac {
// True if we are currently handling an IDC_NEW_{TAB,WINDOW} command. Used in
// SessionService::Observe() to get around windows/linux and mac having
// different models of application lifetime.
bool IsOpeningNewWindow();
// Create a guest profile if one is needed. Afterwards, even if the profile
// already existed, notify the AppController of the profile in use.
void CreateGuestProfileIfNeeded();
// Called when Enterprise startup dialog is close and repost
// applicationDidFinished notification.
void EnterpriseStartupDialogClosed();
// Tells RunInSafeProfile() or RunInSpecificSafeProfile() what to do if the
// profile cannot be loaded from disk.
enum ProfileLoadFailureBehavior {
// Silently fail, and run |callback| with nullptr.
kIgnoreOnFailure,
// Show the profile picker, and run |callback| with nullptr.
kShowProfilePickerOnFailure,
};
// Tries to load the profile returned by |-safeProfileForNewWindows:|. If it
// succeeds, calls |callback| with it.
//
// |callback| must be valid.
void RunInLastProfileSafely(base::OnceCallback<void(Profile*)> callback,
ProfileLoadFailureBehavior on_failure);
// Tries to load the profile in |profile_dir|. If it succeeds, calls
// |callback| with it. If the profile was already loaded, |callback| runs
// immediately.
//
// |callback| must be valid.
void RunInProfileSafely(const base::FilePath& profile_dir,
base::OnceCallback<void(Profile*)> callback,
ProfileLoadFailureBehavior on_failure);
// Allows application to terminate when the last Browser is closed by releasing
// the keep alive object held by the |AppController|. Note that all commands
// received after this call will be ignored, which is OK since the application
// is being terminated anyway.
void AllowApplicationToTerminate();
// Waits for the TabRestoreService to have loaded its entries, then calls
// OpenWindowWithRestoredTabs().
//
// Owned by itself.
class TabRestorer : public sessions::TabRestoreServiceObserver {
public:
// Restore the most recent tab in |profile|, e.g. for Cmd+Shift+T.
static void RestoreMostRecent(Profile* profile);
// Restore a specific tab in |profile|, e.g. for a History menu item.
// |session_id| can be a |tab_restore::Entry::id|, or a
// |TabRestoreEntryService::Entry::original_id|.
static void RestoreByID(Profile* profile, SessionID session_id);
~TabRestorer() override;
// sessions::TabRestoreServiceObserver:
void TabRestoreServiceDestroyed(
sessions::TabRestoreService* service) override;
void TabRestoreServiceLoaded(sessions::TabRestoreService* service) override;
private:
TabRestorer(Profile* profile, SessionID session_id);
// Performs the tab restore. Called either in TabRestoreServiceLoaded(), or
// directly from RestoreMostRecent()/RestoreByID() if the service was already
// loaded.
static void DoRestoreTab(Profile* profile, SessionID session_id);
base::ScopedObservation<sessions::TabRestoreService,
sessions::TabRestoreServiceObserver>
observation_{this};
raw_ptr<Profile> profile_;
SessionID session_id_;
};
// If the current chrome instance is running as a hidden application (with
// activation policy set to NSApplicationActivationPolicyProhibited), after this
// method is called the browser process will no longer keep itself alive as long
// as that is the case.
// This method should be called after chrome is launched as hidden application
// as soon as any other keep-alives have been created to keep the browser
// process alive.
void ResetKeepAliveWhileHidden();
} // namespace app_controller_mac
#endif // CHROME_BROWSER_APP_CONTROLLER_MAC_H_
|