summaryrefslogtreecommitdiffstats
path: root/chrome/browser/app_controller_mac.mm
blob: d7b0a728529155187aa43b9b837808e507c286cb (plain)
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
// 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 "app_controller_mac.h"

#import "base/message_loop.h"
#import "chrome/app/chrome_dll_resource.h"
#import "chrome/browser/browser.h"
#import "chrome/browser/browser_list.h"
#include "chrome/browser/browser_shutdown.h"
#import "chrome/browser/command_updater.h"
#import "chrome/browser/profile_manager.h"
#import "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];
}

- (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 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 {
  // How to get the profile created on line 314 of browser_main? Ugh. TODO:FIXME
  Profile* default_profile = *g_browser_process->profile_manager()->begin();
  
  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;
  };
}

- (void)initMenuState {
  menuState_ = new CommandUpdater(NULL);
  menuState_->UpdateCommandEnabled(IDC_NEW_WINDOW, true);
  menuState_->UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
  // TODO(pinkerton): ...more to come...
}

@end