summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/chrome_command_ids.h3
-rw-r--r--chrome/browser/app_controller_mac.mm64
-rw-r--r--chrome/browser/app_controller_mac_unittest.mm2
-rw-r--r--chrome/browser/background_application_list_model.cc11
4 files changed, 73 insertions, 7 deletions
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index dccebfa..926088d 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -5,6 +5,9 @@
// This file lists all the command IDs understood by e.g. the browser.
// It is used by Windows RC files, Mac NIB files, and other platforms too.
+// Values below IDC_MinimumLabelValue are reserved for dynamic menu items.
+#define IDC_MinimumLabelValue 4000
+
#define IDC_Messages 4000
#define IDC_MessagesAll 4007
#define IDC_MessagesNone 4008
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index c25cdff..428f375 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -14,6 +14,7 @@
#include "base/string_number_conversions.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/background_application_list_model.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser_thread.h"
@@ -154,6 +155,7 @@ void RecordLastRunAppBundlePath() {
- (void)showPreferencesWindow:(id)sender
page:(OptionsPage)page
profile:(Profile*)profile;
+- (void)executeApplication:(id)sender;
@end
@implementation AppController
@@ -792,7 +794,7 @@ void RecordLastRunAppBundlePath() {
enable = YES;
} else if (action == @selector(orderFrontStandardAboutPanel:)) {
enable = YES;
- } else if (action == @selector(newWindowFromDock:)) {
+ } else if (action == @selector(commandFromDock:)) {
enable = YES;
}
return enable;
@@ -928,7 +930,30 @@ void RecordLastRunAppBundlePath() {
case IDC_OPTIONS:
[self showPreferences:sender];
break;
+ default:
+ // Background Applications use dynamic values that must be less than the
+ // smallest value among the predefined IDC_* labels.
+ if ([sender tag] < IDC_MinimumLabelValue)
+ [self executeApplication:sender];
+ break;
+ }
+}
+
+// Run a (background) application in a new tab.
+- (void)executeApplication:(id)sender {
+ NSInteger tag = [sender tag];
+ Profile* profile = [self defaultProfile];
+ DCHECK(profile);
+ BackgroundApplicationListModel applications(profile);
+ DCHECK(tag >= 0 &&
+ tag < static_cast<int>(applications.size()));
+ Browser* browser = BrowserList::GetLastActive();
+ if (!browser) {
+ Browser::OpenEmptyWindow(profile);
+ browser = BrowserList::GetLastActive();
}
+ const Extension* extension = applications.GetExtension(tag);
+ browser->OpenApplicationTab(profile, extension, NULL);
}
// Same as |-commandDispatch:|, but executes commands using a disposition
@@ -1162,25 +1187,52 @@ void RecordLastRunAppBundlePath() {
}
// Explicitly bring to the foreground when creating new windows from the dock.
-- (void)newWindowFromDock:(id)sender {
+- (void)commandFromDock:(id)sender {
[NSApp activateIgnoringOtherApps:YES];
[self commandDispatch:sender];
}
- (NSMenu*)applicationDockMenu:(NSApplication*)sender {
NSMenu* dockMenu = [[[NSMenu alloc] initWithTitle: @""] autorelease];
+ Profile* profile = [self defaultProfile];
+
+ // TODO(rickcam): Mock out BackgroundApplicationListModel, then add unit
+ // tests which use the mock in place of the profile-initialized model.
+
+ // Avoid breaking unit tests which have no profile.
+ if (profile) {
+ int position = 0;
+ BackgroundApplicationListModel applications(profile);
+ for (ExtensionList::const_iterator cursor = applications.begin();
+ cursor != applications.end();
+ ++cursor, ++position) {
+ DCHECK(position == applications.GetPosition(*cursor));
+ scoped_nsobject<NSMenuItem> appItem([[NSMenuItem alloc]
+ initWithTitle:base::SysUTF16ToNSString(UTF8ToUTF16((*cursor)->name()))
+ action:@selector(commandFromDock:)
+ keyEquivalent:@""]);
+ [appItem setTarget:self];
+ [appItem setTag:position];
+ [dockMenu addItem:appItem];
+ }
+ if (applications.begin() != applications.end()) {
+ NSMenuItem* sepItem = [[NSMenuItem separatorItem] init];
+ [dockMenu addItem:sepItem];
+ }
+ }
+
NSString* titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_WINDOW_MAC);
scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
- initWithTitle:titleStr
- action:@selector(newWindowFromDock:)
- keyEquivalent:@""]);
+ initWithTitle:titleStr
+ action:@selector(commandFromDock:)
+ keyEquivalent:@""]);
[item setTarget:self];
[item setTag:IDC_NEW_WINDOW];
[dockMenu addItem:item];
titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_INCOGNITO_WINDOW_MAC);
item.reset([[NSMenuItem alloc] initWithTitle:titleStr
- action:@selector(newWindowFromDock:)
+ action:@selector(commandFromDock:)
keyEquivalent:@""]);
[item setTarget:self];
[item setTag:IDC_NEW_INCOGNITO_WINDOW];
diff --git a/chrome/browser/app_controller_mac_unittest.mm b/chrome/browser/app_controller_mac_unittest.mm
index 6af8e13..88e8de3 100644
--- a/chrome/browser/app_controller_mac_unittest.mm
+++ b/chrome/browser/app_controller_mac_unittest.mm
@@ -22,6 +22,6 @@ TEST_F(AppControllerTest, DockMenu) {
EXPECT_NE(-1, [menu indexOfItemWithTag:IDC_NEW_INCOGNITO_WINDOW]);
for (item in [menu itemArray]) {
EXPECT_EQ(ac.get(), [item target]);
- EXPECT_EQ(@selector(newWindowFromDock:), [item action]);
+ EXPECT_EQ(@selector(commandFromDock:), [item action]);
}
}
diff --git a/chrome/browser/background_application_list_model.cc b/chrome/browser/background_application_list_model.cc
index 4a2a617..eac2577 100644
--- a/chrome/browser/background_application_list_model.cc
+++ b/chrome/browser/background_application_list_model.cc
@@ -10,6 +10,7 @@
#include "app/l10n_util_collator.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_prefs.h"
@@ -157,6 +158,9 @@ BackgroundApplicationListModel::BackgroundApplicationListModel(Profile* profile)
registrar_.Add(this,
NotificationType::EXTENSIONS_READY,
Source<Profile>(profile));
+ ExtensionService* service = profile->GetExtensionService();
+ if (service && service->is_ready())
+ Update();
}
void BackgroundApplicationListModel::AddObserver(Observer* observer) {
@@ -168,6 +172,13 @@ void BackgroundApplicationListModel::AssociateApplicationData(
DCHECK(IsBackgroundApp(*extension));
Application* application = FindApplication(extension);
if (!application) {
+ // App position is used as a dynamic command and so must be less than any
+ // predefined command id.
+ if (applications_.size() >= IDC_MinimumLabelValue) {
+ LOG(ERROR) << "Background application limit of " << IDC_MinimumLabelValue
+ << " exceeded. Ignoring.";
+ return;
+ }
application = new Application(this, extension);
applications_[extension->id()] = application;
application->RequestIcon(Extension::EXTENSION_ICON_BITTY);