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
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/app_controller_mac.h"
#include "base/message_loop.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_shutdown.h"
#import "chrome/browser/cocoa/bookmark_menu_bridge.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/temp_scaffolding_stubs.h"
@interface AppController(PRIVATE)
- (void)initMenuState;
@end
@implementation AppController
- (void)awakeFromNib {
// Set up the command updater for when there are no windows open
[self initMenuState];
bookmarkMenuBridge_ = new BookmarkMenuBridge();
}
- (void)applicationDidFinishLaunching:(NSNotification*)notify {
// Hold an extra ref to the BrowserProcess singleton so it doesn't go away
// when all the browser windows get closed. We'll release it on quit which
// will be the signal to exit.
DCHECK(g_browser_process);
g_browser_process->AddRefModule();
}
- (void)dealloc {
delete bookmarkMenuBridge_;
delete menuState_;
[super dealloc];
}
// We can't use the standard terminate: method because it will abruptly exit
// the app and leave things on the stack in an unfinalized state. We need to
// post a quit message to our run loop so the stack can gracefully unwind.
- (IBAction)quit:(id)sender {
// TODO(pinkerton):
// since we have to roll it ourselves, ask the delegate (ourselves, really)
// if we should terminate. For example, we might not want to if the user
// has ongoing downloads or multiple windows/tabs open. However, this would
// require posting UI and may require spinning up another run loop to
// handle it. If it says to continue, post the quit message, otherwise
// go back to normal.
// TODO(pinkerton): Not sure where this should live, including it here
// causes all sorts of asserts from the open renderers. On Windows, it
// lives in Browser::OnWindowClosing, but that's not appropriate on Mac
// since we don't shut down when we reach zero windows.
// browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
// Close all the windows.
BrowserList::CloseAllBrowsers(true);
// Release the reference to the browser process. Once all the browsers get
// dealloc'd, it will stop the RunLoop and fall back into main().
g_browser_process->ReleaseModule();
}
// Called to validate menu items when there are no key windows. All the
// items we care about have been set with the |commandDispatch:| action and
// a target of FirstResponder in IB. If it's not one of those, let it
// continue up the responder chain to be handled elsewhere. We pull out the
// tag as the cross-platform constant to differentiate and dispatch the
// various commands.
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
SEL action = [item action];
BOOL enable = NO;
if (action == @selector(commandDispatch:)) {
NSInteger tag = [item tag];
if (menuState_->SupportsCommand(tag))
enable = menuState_->IsCommandEnabled(tag) ? YES : NO;
} else if (action == @selector(quit:)) {
enable = YES;
}
return enable;
}
// Called when the user picks a menu item when there are no key windows. Calls
// through to the browser object to execute the command. This assumes that the
// command is supported and doesn't check, otherwise it would have been disabled
// in the UI in validateUserInterfaceItem:.
- (void)commandDispatch:(id)sender {
Profile* default_profile = [self defaultProfile];
NSInteger tag = [sender tag];
switch (tag) {
case IDC_NEW_WINDOW:
Browser::OpenEmptyWindow(default_profile);
break;
case IDC_NEW_INCOGNITO_WINDOW:
Browser::OpenURLOffTheRecord(default_profile, GURL());
break;
};
}
// NSApplication delegate method called when someone clicks on the
// dock icon and there are no open windows. To match standard mac
// behavior, we should open a new window.
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication
hasVisibleWindows:(BOOL)flag {
// Don't do anything if there are visible windows. This will cause
// AppKit to unminimize the most recently minimized window.
if (flag)
return YES;
// Otherwise open a new window.
Browser::OpenEmptyWindow([self defaultProfile]);
// We've handled the reopen event, so return NO to tell AppKit not
// to do anything.
return NO;
}
- (void)initMenuState {
menuState_ = new CommandUpdater(NULL);
menuState_->UpdateCommandEnabled(IDC_NEW_WINDOW, true);
menuState_->UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
// TODO(pinkerton): ...more to come...
}
- (Profile*)defaultProfile {
// Only expected to return NULL in a unit test (if g_browser_process
// is a TestingBrowserProcess).
// TODO(jrg): DCHECK() to confirm that.
// TODO(jrg): Find a better way to get the "default" profile.
if (g_browser_process->profile_manager())
return *g_browser_process->profile_manager()->begin();
return NULL;
}
@end
|