Mac: when only minimized windows present, various commands should unminimize ...

... and use an existing window rather than create a new one. Also, when a dialog
box (e.g., Preferences, Bookmark Manager, etc.) is active, those commands should
activate an existing window (if one exists) instead of always creating a new
window.

The complete list of commands which should activate a miniaturized window if
possible (otherwise create a new window):
- File->New Tab (Cmd-T)
- File->Open Location... (Cmd-L)
- Edit->Find->Search the Web... (Opt-Cmd-F)
- History->History (Cmd-Y)
- Window->Downloads (Shift-Cmd-J)
- Window->Extensions
- Help->Chromium/Google Chrome Help
For now, I'm letting File->Open File... (Cmd-O) always create a new window,
which is consistent with Safari.

BUG=21434
TEST=Close all windows; try one of the commands above (in commit message/CL description); a new window should be created and the command should work; this is all as before this CL. Create a window (if necessary) and minimize all browser windows; try one of the commands above; the last-active browser window should unminimize and the command should execute in that window.

Review URL: http://codereview.chromium.org/652018

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39566 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index acf1480..75dc5cb 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -5,6 +5,7 @@
 #import "chrome/browser/app_controller_mac.h"
 
 #include "app/l10n_util_mac.h"
+#include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/mac_util.h"
 #include "base/message_loop.h"
@@ -58,9 +59,52 @@
 @end
 #endif
 
-@interface AppController(PRIVATE)
+namespace {
+
+// True while AppController is calling Browser::OpenEmptyWindow(). We need a
+// global flag here, analogue to BrowserInit::InProcessStartup() because
+// otherwise the SessionService will try to restore sessions when we make a new
+// window while there are no other active windows.
+bool g_is_opening_new_window = false;
+
+// Activates a browser window having the given profile (the last one active) if
+// possible and returns a pointer to the activate |Browser| or NULL if this was
+// not possible. If the last active browser is minimized (in particular, if
+// there are only minimized windows), it will unminimize it.
+Browser* ActivateBrowser(Profile* profile) {
+  Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
+  if (browser)
+    browser->window()->Activate();
+  return browser;
+}
+
+// Creates an empty browser window with the given profile and returns a pointer
+// to the new |Browser|.
+Browser* CreateBrowser(Profile* profile) {
+  {
+    AutoReset auto_reset_in_run(&g_is_opening_new_window, true);
+    Browser::OpenEmptyWindow(profile);
+  }
+
+  Browser* browser = BrowserList::GetLastActive();
+  CHECK(browser);
+  return browser;
+}
+
+// Activates a browser window having the given profile (the last one active) if
+// possible or creates an empty one if necessary. Returns a pointer to the
+// activated/new |Browser|.
+Browser* ActivateOrCreateBrowser(Profile* profile) {
+  if (Browser* browser = ActivateBrowser(profile))
+    return browser;
+  return CreateBrowser(profile);
+}
+
+}  // anonymous namespace
+
+@interface AppController(Private)
 - (void)initMenuState;
-- (void)openURLs:(const std::vector<GURL>&)urls;
+- (void)openUrls:(const std::vector<GURL>&)urls;
 - (void)getUrl:(NSAppleEventDescriptor*)event
      withReply:(NSAppleEventDescriptor*)reply;
 - (void)windowLayeringDidChange:(NSNotification*)inNotification;
@@ -71,12 +115,6 @@
                       profile:(Profile*)profile;
 @end
 
-// True while AppController is calling Browser::OpenEmptyWindow(). We need a
-// global flag here, analogue to BrowserInit::InProcessStartup() because
-// otherwise the SessionService will try to restore sessions when we make a new
-// window while there are no other active windows.
-static bool g_is_opening_new_window = false;
-
 @implementation AppController
 
 @synthesize startupComplete = startupComplete_;
@@ -352,9 +390,9 @@
   // TODO(viettrungluu): This is very temporary, since this should be done "in"
   // |BrowserMain()|, i.e., this list of startup URLs should be appended to the
   // (probably-empty) list of URLs from the command line.
-  if (startupURLs_.size()) {
-    [self openURLs:startupURLs_];
-    [self clearStartupURLs];
+  if (startupUrls_.size()) {
+    [self openUrls:startupUrls_];
+    [self clearStartupUrls];
   }
 }
 
@@ -523,8 +561,8 @@
 // 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 would have been disabled in the UI in
-// validateUserInterfaceItem:.
+// check, otherwise it should have been disabled in the UI in
+// |-validateUserInterfaceItem:|.
 - (void)commandDispatch:(id)sender {
   Profile* defaultProfile = [self defaultProfile];
 
@@ -542,17 +580,22 @@
   NSInteger tag = [sender tag];
   switch (tag) {
     case IDC_NEW_TAB:
+      // Create a new tab in an existing browser window (which we activate) if
+      // possible.
+      if (Browser* browser = ActivateBrowser(defaultProfile)) {
+        browser->ExecuteCommand(IDC_NEW_TAB);
+        break;
+      }
+      // Else fall through to create new window.
     case IDC_NEW_WINDOW:
+      CreateBrowser(defaultProfile);
+      break;
     case IDC_FOCUS_LOCATION:
-      g_is_opening_new_window = true;
-      Browser::OpenEmptyWindow(defaultProfile);
-      g_is_opening_new_window = false;
+      ActivateOrCreateBrowser(defaultProfile)->
+          ExecuteCommand(IDC_FOCUS_LOCATION);
       break;
     case IDC_FOCUS_SEARCH:
-      g_is_opening_new_window = true;
-      Browser::OpenEmptyWindow(defaultProfile);
-      g_is_opening_new_window = false;
-      BrowserList::GetLastActive()->FocusSearch();
+      ActivateOrCreateBrowser(defaultProfile)->ExecuteCommand(IDC_FOCUS_SEARCH);
       break;
     case IDC_NEW_INCOGNITO_WINDOW:
       Browser::OpenEmptyWindow(defaultProfile->GetOffTheRecordProfile());
@@ -561,11 +604,7 @@
       Browser::OpenWindowWithRestoredTabs(defaultProfile);
       break;
     case IDC_OPEN_FILE:
-      g_is_opening_new_window = true;
-      Browser::OpenEmptyWindow(defaultProfile);
-      g_is_opening_new_window = false;
-      BrowserList::GetLastActive()->
-          ExecuteCommandWithDisposition(IDC_OPEN_FILE, CURRENT_TAB);
+      CreateBrowser(defaultProfile)->ExecuteCommand(IDC_OPEN_FILE);
       break;
     case IDC_CLEAR_BROWSING_DATA: {
       // There may not be a browser open, so use the default profile.
@@ -584,25 +623,37 @@
       [BookmarkManagerController showBookmarkManager:defaultProfile];
       break;
     case IDC_SHOW_HISTORY:
-      Browser::OpenHistoryWindow(defaultProfile);
+      if (Browser* browser = ActivateBrowser(defaultProfile))
+        browser->ShowHistoryTab();
+      else
+        Browser::OpenHistoryWindow(defaultProfile);
       break;
     case IDC_SHOW_DOWNLOADS:
-      Browser::OpenDownloadsWindow(defaultProfile);
+      if (Browser* browser = ActivateBrowser(defaultProfile))
+        browser->ShowDownloadsTab();
+      else
+        Browser::OpenDownloadsWindow(defaultProfile);
       break;
     case IDC_MANAGE_EXTENSIONS:
-      Browser::OpenExtensionsWindow(defaultProfile);
+      if (Browser* browser = ActivateBrowser(defaultProfile))
+        browser->ShowExtensionsTab();
+      else
+        Browser::OpenExtensionsWindow(defaultProfile);
       break;
     case IDC_HELP_PAGE:
-      Browser::OpenHelpWindow(defaultProfile);
+      if (Browser* browser = ActivateBrowser(defaultProfile))
+        browser->OpenHelpTab();
+      else
+        Browser::OpenHelpWindow(defaultProfile);
       break;
     case IDC_REPORT_BUG: {
       Browser* browser = BrowserList::GetLastActive();
-      TabContents* current_tab = (browser != NULL) ?
-          browser->GetSelectedTabContents() : NULL;
+      TabContents* currentTab =
+          browser ? browser->GetSelectedTabContents() : NULL;
       BugReportWindowController* controller =
           [[BugReportWindowController alloc]
-          initWithTabContents:current_tab
-                      profile:[self defaultProfile]];
+              initWithTabContents:currentTab
+                          profile:[self defaultProfile]];
       [controller runModalDialog];
       break;
     }
@@ -616,7 +667,7 @@
       UserMetrics::RecordAction("TaskManager", defaultProfile);
       TaskManagerMac::Show();
       break;
-  };
+  }
 }
 
 // Same as |-commandDispatch:|, but executes commands using a disposition
@@ -645,9 +696,10 @@
     return YES;
 
   // Otherwise open a new window.
-  g_is_opening_new_window = true;
-  Browser::OpenEmptyWindow([self defaultProfile]);
-  g_is_opening_new_window = false;
+  {
+    AutoReset auto_reset_in_run(&g_is_opening_new_window, true);
+    Browser::OpenEmptyWindow([self defaultProfile]);
+  }
 
   // We've handled the reopen event, so return NO to tell AppKit not
   // to do anything.
@@ -689,10 +741,10 @@
 // the ProcessSingleton, and it calls BrowserInit. It's best to bottleneck the
 // openings through that for uniform handling.
 
-- (void)openURLs:(const std::vector<GURL>&)urls {
+- (void)openUrls:(const std::vector<GURL>&)urls {
   // If the browser hasn't started yet, just queue up the URLs.
   if (!startupComplete_) {
-    startupURLs_.insert(startupURLs_.end(), urls.begin(), urls.end());
+    startupUrls_.insert(startupUrls_.end(), urls.begin(), urls.end());
     return;
   }
 
@@ -717,7 +769,7 @@
   std::vector<GURL> gurlVector;
   gurlVector.push_back(gurl);
 
-  [self openURLs:gurlVector];
+  [self openUrls:gurlVector];
 }
 
 - (void)application:(NSApplication*)sender
@@ -728,7 +780,7 @@
     gurlVector.push_back(gurl);
   }
   if (!gurlVector.empty())
-    [self openURLs:gurlVector];
+    [self openUrls:gurlVector];
   else
     NOTREACHED() << "Nothing to open!";
 
@@ -836,15 +888,15 @@
   return dockMenu;
 }
 
-- (const std::vector<GURL>&)startupURLs {
-  return startupURLs_;
+- (const std::vector<GURL>&)startupUrls {
+  return startupUrls_;
 }
 
-- (void)clearStartupURLs {
-  startupURLs_.clear();
+- (void)clearStartupUrls {
+  startupUrls_.clear();
 }
 
-@end
+@end  // @implementation AppController
 
 //---------------------------------------------------------------------------