chromeos: Add maximize/restore button.

This makes Chrome watch the _CHROME_LAYOUT_MODE property
that the window manager now sets on the root window and use
it to update the state of a new button to the right of the
status area that can be used to toggle between having
maximized or overlapping browser windows.

BUG=chromium-os:13963
TEST=manual


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90804 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index fd5f9af8..3fce9e4 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -11730,9 +11730,6 @@
       <message name="IDS_STATUSBAR_WINDOW_RESTORE_TOOLTIP" desc="Tooltip for the layout mode button in the status bar when the window is maximized.">
         Restore
       </message>
-      <message name="IDS_STATUSBAR_WINDOW_SWITCHER_TOOLTIP" desc="Tooltip for the window switcher in the status bar.">
-        Switch windows
-      </message>
       <message name="IDS_VERSION_FIELD_PREFIX" desc="Display the OS version to the user.">
         version
       </message>
diff --git a/chrome/app/theme/statusbar_window_center.png b/chrome/app/theme/statusbar_window_center.png
deleted file mode 100644
index ce3941c..0000000
--- a/chrome/app/theme/statusbar_window_center.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/statusbar_window_left.png b/chrome/app/theme/statusbar_window_left.png
deleted file mode 100644
index 10baa2d..0000000
--- a/chrome/app/theme/statusbar_window_left.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/statusbar_window_right.png b/chrome/app/theme/statusbar_window_right.png
deleted file mode 100644
index 021ef233..0000000
--- a/chrome/app/theme/statusbar_window_right.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/statusbar_window_switcher.png b/chrome/app/theme/statusbar_window_switcher.png
deleted file mode 100644
index c923fc97a..0000000
--- a/chrome/app/theme/statusbar_window_switcher.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 2a32010c6..91e3dbc0 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -564,7 +564,6 @@
         <include name="IDR_STATUSBAR_WINDOW_RESTORE" file="statusbar_window_restore.png" type="BINDATA" />
         <include name="IDR_STATUSBAR_WIRED" file="statusbar_wired.png" type="BINDATA" />
         <include name="IDR_STATUSBAR_WIRED_BLACK" file="statusbar_wiredb.png" type="BINDATA" />
-        <include name="IDR_STATUSBAR_WINDOW_SWITCHER" file="statusbar_window_switcher.png" type="BINDATA" />
         <include name="IDR_USER_IMAGE_NO_VIDEO" file="no_video.png" type="BINDATA" />
         <include name="IDR_USER_IMAGE_CAPTURE" file="snapshot_wide.png" type="BINDATA" />
         <include name="IDR_USER_IMAGE_RECYCLE" file="discard_wide.png" type="BINDATA" />
diff --git a/chrome/browser/chromeos/frame/browser_frame_chromeos.cc b/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
deleted file mode 100644
index 7d09f01c..0000000
--- a/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2011 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.
-
-#include "chrome/browser/chromeos/frame/browser_frame_chromeos.h"
-
-#include "base/command_line.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
-#include "chrome/common/chrome_switches.h"
-
-// static (Factory method.)
-BrowserFrame* BrowserFrame::Create(BrowserView* browser_view,
-                                   Profile* profile) {
-  chromeos::BrowserFrameChromeos* frame =
-      new chromeos::BrowserFrameChromeos(browser_view, profile);
-  frame->InitBrowserFrame();
-  return frame;
-}
-
-namespace chromeos {
-
-BrowserFrameChromeos::BrowserFrameChromeos(
-    BrowserView* browser_view, Profile* profile)
-    : BrowserFrameGtk(browser_view, profile) {
-}
-
-BrowserFrameChromeos::~BrowserFrameChromeos() {
-}
-
-void BrowserFrameChromeos::InitBrowserFrame() {
-  BrowserFrameGtk::InitBrowserFrame();
-
-  if (!browser_view()->IsBrowserTypePopup() &&
-      !browser_view()->IsBrowserTypePanel()) {
-    // On chromeos we want windows to always render as active.
-    DisableInactiveRendering();
-  }
-}
-
-bool BrowserFrameChromeos::IsMaximized() const {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeosFrame))
-    return NativeWidgetGtk::IsMaximized();
-  bool is_popup_or_panel = browser_view()->IsBrowserTypePopup() ||
-                           browser_view()->IsBrowserTypePanel();
-  return !IsFullscreen() &&
-      (!is_popup_or_panel || NativeWidgetGtk::IsMaximized());
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/frame/browser_frame_chromeos.h b/chrome/browser/chromeos/frame/browser_frame_chromeos.h
deleted file mode 100644
index bb4edbc..0000000
--- a/chrome/browser/chromeos/frame/browser_frame_chromeos.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2011 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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_FRAME_CHROMEOS_H_
-#define CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_FRAME_CHROMEOS_H_
-#pragma once
-
-#include "chrome/browser/ui/views/frame/browser_frame_gtk.h"
-
-namespace chromeos {
-
-class BrowserFrameChromeos : public BrowserFrameGtk {
- public:
-  BrowserFrameChromeos(BrowserView* browser_view, Profile* profile);
-  virtual ~BrowserFrameChromeos();
-
-  // BrowserFrameGtk overrides.
-  virtual void InitBrowserFrame();
-
-  // views::NativeWidgetGtk overrides.
-  virtual bool IsMaximized() const;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserFrameChromeos);
-};
-
-}  // namespace chroemos
-
-#endif  // CHROME_BROWSER_CHROMEOS_FRAME_BROWSER_FRAME_CHROMEOS_H_
diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc
index 191577f..5d177d5 100644
--- a/chrome/browser/chromeos/frame/browser_view.cc
+++ b/chrome/browser/chromeos/frame/browser_view.cc
@@ -11,6 +11,7 @@
 
 #include "base/command_line.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/chromeos/frame/layout_mode_button.h"
 #include "chrome/browser/chromeos/frame/panel_browser_view.h"
 #include "chrome/browser/chromeos/status/input_method_menu_button.h"
 #include "chrome/browser/chromeos/status/network_menu_button.h"
@@ -113,10 +114,10 @@
 
 namespace chromeos {
 
-// LayoutManager for BrowserView, which layouts extra components such as
+// LayoutManager for BrowserView, which lays out extra components such as
 // the status views as follows:
 //       ____  __ __
-//      /    \   \  \     [StatusArea]
+//      /    \   \  \     [StatusArea] [LayoutModeButton]
 //
 class BrowserViewLayout : public ::BrowserViewLayout {
  public:
@@ -128,6 +129,7 @@
 
   void Installed(views::View* host) {
     status_area_ = NULL;
+    layout_mode_button_ = NULL;
     ::BrowserViewLayout::Installed(host);
   }
 
@@ -138,17 +140,22 @@
       case VIEW_ID_STATUS_AREA:
         status_area_ = static_cast<chromeos::StatusAreaView*>(view);
         break;
+      case VIEW_ID_LAYOUT_MODE_BUTTON:
+        layout_mode_button_ = static_cast<chromeos::LayoutModeButton*>(view);
+        break;
     }
   }
 
   // In the normal and the compact navigation bar mode, ChromeOS
-  // layouts compact navigation buttons and status views in the title
+  // lays out compact navigation buttons and status views in the title
   // area. See Layout
   virtual int LayoutTabStripRegion() OVERRIDE {
     if (browser_view_->IsFullscreen() || !browser_view_->IsTabStripVisible()) {
       status_area_->SetVisible(false);
       tabstrip_->SetVisible(false);
       tabstrip_->SetBounds(0, 0, 0, 0);
+      layout_mode_button_->SetVisible(false);
+      layout_mode_button_->SetBounds(0, 0, 0, 0);
       return 0;
     }
 
@@ -202,6 +209,12 @@
     if (status_area_->HitTest(point_in_status_area_coords))
       return true;
 
+    gfx::Point point_in_layout_mode_button_coords(point);
+    views::View::ConvertPointToView(browser_view_, layout_mode_button_,
+                                    &point_in_layout_mode_button_coords);
+    if (layout_mode_button_->HitTest(point_in_layout_mode_button_coords))
+      return true;
+
     return false;
   }
 
@@ -213,6 +226,8 @@
 
     tabstrip_->SetVisible(true);
     status_area_->SetVisible(true);
+    layout_mode_button_->SetVisible(false);
+    layout_mode_button_->SetBounds(0, 0, 0, 0);
 
     gfx::Size status_size = status_area_->GetPreferredSize();
     int status_height = status_size.height();
@@ -222,7 +237,7 @@
     status_area_->SetBounds(status_x, bounds.bottom() - status_height,
                             status_size.width(), status_height);
 
-    // The tabstrip's width is the bigger of it's preferred width and the width
+    // The tabstrip's width is the bigger of its preferred width and the width
     // the status area.
     int tabstrip_w = std::max(status_x + status_size.width(),
                               tabstrip_->GetPreferredSize().width());
@@ -249,20 +264,37 @@
     return bounds.y() + toolbar_height;
   }
 
-  // Lays out tabstrip and status area in the title bar area (given by
-  // |bounds|).
+  // Lays out tabstrip, status area, and layout mode button in the title bar
+  // area (given by |bounds|).
   int LayoutTitlebarComponents(const gfx::Rect& bounds) {
     if (bounds.IsEmpty())
       return 0;
 
+    const bool show_layout_mode_button =
+        chromeos_browser_view()->should_show_layout_mode_button();
+
     tabstrip_->SetVisible(true);
     status_area_->SetVisible(
         !chromeos_browser_view()->has_hide_status_area_property());
+    layout_mode_button_->SetVisible(show_layout_mode_button);
 
-    // Layout status area after tab strip.
+    const gfx::Size layout_mode_button_size =
+        layout_mode_button_->GetPreferredSize();
+    layout_mode_button_->SetBounds(
+        bounds.right() - layout_mode_button_size.width(),
+        bounds.y(),
+        layout_mode_button_size.width(),
+        layout_mode_button_size.height());
+
+    // Lay out status area after tab strip and before layout mode button (if
+    // shown).
     gfx::Size status_size = status_area_->GetPreferredSize();
+    const int status_right =
+        show_layout_mode_button ?
+        layout_mode_button_->bounds().x() :
+        bounds.right();
     status_area_->SetBounds(
-        bounds.right() - status_size.width(),
+        status_right - status_size.width(),
         bounds.y() + kStatusAreaVerticalAdjustment,
         status_size.width(),
         status_size.height());
@@ -273,6 +305,7 @@
   }
 
   chromeos::StatusAreaView* status_area_;
+  chromeos::LayoutModeButton* layout_mode_button_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserViewLayout);
 };
@@ -282,9 +315,12 @@
 BrowserView::BrowserView(Browser* browser)
     : ::BrowserView(browser),
       status_area_(NULL),
+      layout_mode_button_(NULL),
       saved_focused_widget_(NULL),
-      has_hide_status_area_property_(false) {
+      has_hide_status_area_property_(false),
+      should_show_layout_mode_button_(false) {
   system_menu_delegate_.reset(new SimpleMenuModelDelegateAdapter(this));
+  BrowserList::AddObserver(this);
   MessageLoopForUI::current()->AddObserver(this);
 
   if (!g_chrome_state_gdk_atom)
@@ -298,6 +334,7 @@
   if (toolbar())
     toolbar()->RemoveMenuListener(this);
   MessageLoopForUI::current()->RemoveObserver(this);
+  BrowserList::RemoveObserver(this);
 }
 
 // BrowserView, ::BrowserView overrides:
@@ -309,6 +346,11 @@
   AddChildView(status_area_);
   status_area_->Init();
 
+  layout_mode_button_ = new LayoutModeButton();
+  layout_mode_button_->set_id(VIEW_ID_LAYOUT_MODE_BUTTON);
+  AddChildView(layout_mode_button_);
+  layout_mode_button_->Init();
+
   frame()->non_client_view()->set_context_menu_controller(this);
 
   // Listen to wrench menu opens.
@@ -319,6 +361,7 @@
   gtk_widget_add_events(GTK_WIDGET(frame()->GetNativeWindow()),
                         GDK_PROPERTY_CHANGE_MASK);
   FetchHideStatusAreaProperty();
+  UpdateLayoutModeButtonVisibility();
 
   // Make sure the window is set to the right type.
   std::vector<int> params;
@@ -446,6 +489,22 @@
   saved_focused_widget_ = gtk_window_get_focus(GetNativeHandle());
 }
 
+// BrowserView, BrowserList::Observer implementation.
+
+void BrowserView::OnBrowserAdded(const Browser* browser) {
+  const bool was_showing = should_show_layout_mode_button_;
+  UpdateLayoutModeButtonVisibility();
+  if (should_show_layout_mode_button_ != was_showing)
+    Layout();
+}
+
+void BrowserView::OnBrowserRemoved(const Browser* browser) {
+  const bool was_showing = should_show_layout_mode_button_;
+  UpdateLayoutModeButtonVisibility();
+  if (should_show_layout_mode_button_ != was_showing)
+    Layout();
+}
+
 // BrowserView, StatusAreaHost implementation.
 
 Profile* BrowserView::GetProfile() const {
@@ -542,6 +601,21 @@
   has_hide_status_area_property_ = false;
 }
 
+void BrowserView::UpdateLayoutModeButtonVisibility() {
+  int count = 0;
+  for (BrowserList::const_iterator it = BrowserList::begin();
+       it != BrowserList::end(); ++it) {
+    if ((*it)->is_type_tabbed()) {
+      ++count;
+      if (count >= 2) {
+        should_show_layout_mode_button_ = true;
+        return;
+      }
+    }
+  }
+  should_show_layout_mode_button_ = false;
+}
+
 }  // namespace chromeos
 
 // static
diff --git a/chrome/browser/chromeos/frame/browser_view.h b/chrome/browser/chromeos/frame/browser_view.h
index 9d8e6ec..f2bbc92 100644
--- a/chrome/browser/chromeos/frame/browser_view.h
+++ b/chrome/browser/chromeos/frame/browser_view.h
@@ -10,6 +10,7 @@
 
 #include "base/message_loop.h"
 #include "chrome/browser/chromeos/status/status_area_host.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "views/context_menu_controller.h"
 #include "views/controls/menu/menu_wrapper.h"
@@ -31,6 +32,7 @@
 
 namespace chromeos {
 
+class LayoutModeButton;
 class StatusAreaView;
 class StatusAreaButton;
 
@@ -38,12 +40,13 @@
 // BrowserView created with Browser::TYPE_TABBED. This extender adds controls
 // to the title bar as follows:
 //       ____  __ __
-//      /    \   \  \     [StatusArea]
+//      /    \   \  \     [StatusArea] [LayoutModeButton]
 //
 // and adds the system context menu to the remaining area of the titlebar.
 class BrowserView : public ::BrowserView,
                     public views::ContextMenuController,
                     public views::MenuListener,
+                    public BrowserList::Observer,
                     public StatusAreaHost,
                     public MessageLoopForUI::Observer {
  public:
@@ -72,6 +75,10 @@
   // views::MenuListener implementation.
   virtual void OnMenuOpened() OVERRIDE;
 
+  // BrowserList::Observer implementation.
+  virtual void OnBrowserAdded(const Browser* browser) OVERRIDE;
+  virtual void OnBrowserRemoved(const Browser* browser) OVERRIDE;
+
   // StatusAreaHost overrides.
   virtual Profile* GetProfile() const OVERRIDE;
   virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
@@ -93,6 +100,9 @@
   bool has_hide_status_area_property() const {
     return has_hide_status_area_property_;
   }
+  bool should_show_layout_mode_button() const {
+    return should_show_layout_mode_button_;
+  }
 
   // static implementation for chromeos::PanelBrowserView.
   static WindowOpenDisposition DispositionForPopupBounds(
@@ -110,8 +120,12 @@
   // Updates |has_hide_status_area_property_| by querying the X server.
   void FetchHideStatusAreaProperty();
 
-  // Status Area view.
+  // Updates |should_show_layout_mode_button_|.  Changes won't be visible
+  // onscreen until Layout() is called.
+  void UpdateLayoutModeButtonVisibility();
+
   StatusAreaView* status_area_;
+  LayoutModeButton* layout_mode_button_;
 
   // System menu.
   scoped_ptr<views::MenuItemView> system_menu_;
@@ -126,6 +140,10 @@
   // hide the status area.
   bool has_hide_status_area_property_;
 
+  // Should the layout mode button be shown?  We only show it if there are
+  // multiple browsers open.
+  bool should_show_layout_mode_button_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserView);
 };
 
diff --git a/chrome/browser/chromeos/frame/layout_mode_button.cc b/chrome/browser/chromeos/frame/layout_mode_button.cc
new file mode 100644
index 0000000..ffc2f41
--- /dev/null
+++ b/chrome/browser/chromeos/frame/layout_mode_button.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 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.
+
+#include "chrome/browser/chromeos/frame/layout_mode_button.h"
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/wm_ipc.h"
+#include "content/common/notification_details.h"
+#include "content/common/notification_source.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "views/widget/widget.h"
+
+namespace {
+const int kHorizontalPaddingPixels = 2;
+}  // namespace
+
+namespace chromeos {
+
+LayoutModeButton::LayoutModeButton()
+    : ALLOW_THIS_IN_INITIALIZER_LIST(ImageButton(this)) {
+}
+
+LayoutModeButton::~LayoutModeButton() {
+}
+
+gfx::Size LayoutModeButton::GetPreferredSize() {
+  gfx::Size size = ImageButton::GetPreferredSize();
+  size.Enlarge(2 * kHorizontalPaddingPixels, 0);
+  return size;
+}
+
+bool LayoutModeButton::HitTest(const gfx::Point& l) const {
+  // Handle events above our bounds so that we'll see clicks occuring in the
+  // padding between the top of the screen and the button.
+  const gfx::Point point(l.x(), std::max(y(), l.y()));
+  return ImageButton::HitTest(point);
+}
+
+void LayoutModeButton::Observe(NotificationType type,
+                               const NotificationSource& source,
+                               const NotificationDetails& details) {
+  DCHECK(type == NotificationType::LAYOUT_MODE_CHANGED);
+  UpdateForCurrentLayoutMode();
+}
+
+void LayoutModeButton::Init() {
+  WmIpc* wm_ipc = WmIpc::instance();
+  registrar_.Add(this,
+                 NotificationType::LAYOUT_MODE_CHANGED,
+                 Source<WmIpc>(wm_ipc));
+  UpdateForCurrentLayoutMode();
+}
+
+void LayoutModeButton::ButtonPressed(views::Button* sender,
+                                     const views::Event& event) {
+  DCHECK_EQ(sender, this);
+  WmIpc* wm_ipc = WmIpc::instance();
+  const WmIpcLayoutMode mode = wm_ipc->layout_mode();
+
+  WmIpc::Message message(WM_IPC_MESSAGE_WM_SET_LAYOUT_MODE);
+  switch (mode) {
+    case WM_IPC_LAYOUT_MAXIMIZED:
+      message.set_param(0, WM_IPC_LAYOUT_OVERLAPPING);
+      break;
+    case WM_IPC_LAYOUT_OVERLAPPING:
+      message.set_param(0, WM_IPC_LAYOUT_MAXIMIZED);
+      break;
+    default:
+      DLOG(WARNING) << "Unknown layout mode " << mode;
+      message.set_param(0, WM_IPC_LAYOUT_MAXIMIZED);
+  }
+  wm_ipc->SendMessage(message);
+}
+
+void LayoutModeButton::UpdateForCurrentLayoutMode() {
+  const WmIpcLayoutMode mode = WmIpc::instance()->layout_mode();
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  switch (mode) {
+    case WM_IPC_LAYOUT_MAXIMIZED:
+      SetImage(BS_NORMAL, rb.GetBitmapNamed(IDR_STATUSBAR_WINDOW_RESTORE));
+      SetTooltipText(UTF16ToWide(
+          l10n_util::GetStringUTF16(IDS_STATUSBAR_WINDOW_RESTORE_TOOLTIP)));
+      break;
+    case WM_IPC_LAYOUT_OVERLAPPING:
+      SetImage(BS_NORMAL, rb.GetBitmapNamed(IDR_STATUSBAR_WINDOW_MAXIMIZE));
+      SetTooltipText(UTF16ToWide(
+          l10n_util::GetStringUTF16(IDS_STATUSBAR_WINDOW_MAXIMIZE_TOOLTIP)));
+      break;
+    default:
+      DLOG(WARNING) << "Unknown layout mode " << mode;
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/frame/layout_mode_button.h b/chrome/browser/chromeos/frame/layout_mode_button.h
new file mode 100644
index 0000000..3e7e98d8
--- /dev/null
+++ b/chrome/browser/chromeos/frame/layout_mode_button.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FRAME_LAYOUT_MODE_BUTTON_H_
+#define CHROME_BROWSER_CHROMEOS_FRAME_LAYOUT_MODE_BUTTON_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+#include "views/controls/button/button.h"
+#include "views/controls/button/image_button.h"
+
+class NotificationDetails;
+class NotificationSource;
+
+namespace chromeos {
+
+// Maximize/restore button in the corner of each browser window.
+class LayoutModeButton : public views::ImageButton,
+                         public views::ButtonListener,
+                         public NotificationObserver {
+ public:
+  LayoutModeButton();
+  virtual ~LayoutModeButton();
+
+  // views::* override.
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual bool HitTest(const gfx::Point& l) const OVERRIDE;
+
+  // NotificationObserver implementation.
+  virtual void Observe(NotificationType type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  void Init();
+
+ private:
+  // views::ButtonListener implementation.
+  virtual void ButtonPressed(views::Button* sender, const views::Event& event)
+      OVERRIDE;
+
+  // Update our icon and tooltip appropriately for the current layout mode.
+  void UpdateForCurrentLayoutMode();
+
+  // A registrar for subscribing to LAYOUT_MODE_CHANGED notifications.
+  NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(LayoutModeButton);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FRAME_LAYOUT_MODE_BUTTON_H_
diff --git a/chrome/browser/chromeos/status/status_area_view.cc b/chrome/browser/chromeos/status/status_area_view.cc
index f34e4cd..806c32be 100644
--- a/chrome/browser/chromeos/status/status_area_view.cc
+++ b/chrome/browser/chromeos/status/status_area_view.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/chromeos/status/network_menu_button.h"
 #include "chrome/browser/chromeos/status/power_menu_button.h"
 #include "chrome/browser/chromeos/status/status_area_host.h"
-#include "chrome/browser/chromeos/status/window_switcher_button.h"
 #include "grit/theme_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
@@ -32,8 +31,7 @@
       clock_view_(NULL),
       input_method_view_(NULL),
       network_view_(NULL),
-      power_view_(NULL),
-      window_switcher_view_(NULL) {
+      power_view_(NULL) {
 }
 
 void StatusAreaView::Init() {
@@ -53,10 +51,6 @@
   // Power.
   power_view_ = new PowerMenuButton(host_);
   AddChildView(power_view_);
-
-  // Window Switcher.
-  window_switcher_view_ = new WindowSwitcherButton(host_);
-  AddChildView(window_switcher_view_);
 }
 
 gfx::Size StatusAreaView::GetPreferredSize() {
diff --git a/chrome/browser/chromeos/status/status_area_view.h b/chrome/browser/chromeos/status/status_area_view.h
index 1b858f7..23b7ae9 100644
--- a/chrome/browser/chromeos/status/status_area_view.h
+++ b/chrome/browser/chromeos/status/status_area_view.h
@@ -17,7 +17,6 @@
 class NetworkMenuButton;
 class PowerMenuButton;
 class StatusAreaHost;
-class WindowSwitcherButton;
 
 // This class is used to wrap the small informative widgets in the upper-right
 // of the window title bar. It is used on ChromeOS only.
@@ -38,9 +37,6 @@
   InputMethodMenuButton* input_method_view() { return input_method_view_; }
   NetworkMenuButton* network_view() { return network_view_; }
   PowerMenuButton* power_view() { return power_view_; }
-  WindowSwitcherButton* window_switcher_view() {
-    return window_switcher_view_;
-  }
 
  private:
   StatusAreaHost* host_;
@@ -49,7 +45,6 @@
   InputMethodMenuButton* input_method_view_;
   NetworkMenuButton* network_view_;
   PowerMenuButton* power_view_;
-  WindowSwitcherButton* window_switcher_view_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusAreaView);
 };
diff --git a/chrome/browser/chromeos/status/window_switcher_button.cc b/chrome/browser/chromeos/status/window_switcher_button.cc
deleted file mode 100644
index f51129d..0000000
--- a/chrome/browser/chromeos/status/window_switcher_button.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2011 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.
-
-#include "chrome/browser/chromeos/status/window_switcher_button.h"
-
-#include "chrome/browser/chromeos/status/status_area_host.h"
-#include "chrome/browser/chromeos/wm_ipc.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-
-namespace chromeos {
-
-namespace {
-int GetNormalBrowserCount() {
-  int count = 0;
-  BrowserList::const_iterator iter;
-  for (iter = BrowserList::begin(); iter != BrowserList::end(); ++iter) {
-    if ((*iter)->is_type_tabbed())
-      count++;
-  }
-  return count;
-}
-}
-
-WindowSwitcherButton::WindowSwitcherButton(StatusAreaHost* host)
-    : StatusAreaButton(host, this) {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_WINDOW_SWITCHER));
-  SetEnabled(true);
-
-  UpdateStatus();
-  BrowserList::AddObserver(this);
-}
-
-WindowSwitcherButton::~WindowSwitcherButton() {
-  BrowserList::RemoveObserver(this);
-}
-
-void WindowSwitcherButton::UpdateStatus() {
-  if (GetNormalBrowserCount() < 2) {
-    // There are less than two browsers.  This means we can't switch
-    // anywhere, so we disappear.
-    SetTooltipText(L"");
-    SetVisible(false);
-    PreferredSizeChanged();
-    return;
-  }
-
-  SetTooltipText(UTF16ToWide(l10n_util::GetStringUTF16(
-      IDS_STATUSBAR_WINDOW_SWITCHER_TOOLTIP)));
-
-  // There are at least two browsers, so we show ourselves.
-  SetVisible(true);
-  PreferredSizeChanged();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WindowSwitcherButton, views::ViewMenuDelegate implementation:
-
-void WindowSwitcherButton::RunMenu(views::View* source, const gfx::Point& pt) {
-  // Don't do anything if there aren't at least two normal browsers to
-  // switch between.
-  if (GetNormalBrowserCount() < 2)
-    return;
-
-  // Send a message to the ChromeOS window manager to switch to the
-  // next top level browser window.  Only the window manager knows
-  // what order they are in, so we can't use Chrome's browser list
-  // to decide.
-  WmIpc::Message message(chromeos::WM_IPC_MESSAGE_WM_CYCLE_WINDOWS);
-  message.set_param(0, true);
-  WmIpc::instance()->SendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// BrowserList::Observer implementation:
-
-// Called immediately after a browser is added to the list
-void WindowSwitcherButton::OnBrowserAdded(const Browser* browser) {
-  UpdateStatus();
-}
-
-// Called immediately after a browser is removed from the list
-void WindowSwitcherButton::OnBrowserRemoved(const Browser* browser) {
-  UpdateStatus();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/status/window_switcher_button.h b/chrome/browser/chromeos/status/window_switcher_button.h
deleted file mode 100644
index 7ed086d..0000000
--- a/chrome/browser/chromeos/status/window_switcher_button.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2011 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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_STATUS_WINDOW_SWITCHER_BUTTON_H_
-#define CHROME_BROWSER_CHROMEOS_STATUS_WINDOW_SWITCHER_BUTTON_H_
-#pragma once
-
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/status/status_area_button.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "content/common/notification_observer.h"
-#include "views/controls/button/menu_button.h"
-#include "views/controls/menu/view_menu_delegate.h"
-
-namespace chromeos {
-
-class StatusAreaHost;
-
-// The window switcher button in the status area.  This button allows
-// the user to move to the next window if they click on the icon.
-class WindowSwitcherButton : public StatusAreaButton,
-                             public views::ViewMenuDelegate,
-                             public BrowserList::Observer {
- public:
-  explicit WindowSwitcherButton(StatusAreaHost* host);
-  virtual ~WindowSwitcherButton();
-
- private:
-  // Updates the status of the button based on the state of the
-  // browser list.
-  void UpdateStatus();
-
-  // BrowserList::Observer API
-  virtual void OnBrowserAdded(const Browser* browser);
-  virtual void OnBrowserRemoved(const Browser* browser);
-
-  // views::ViewMenuDelegate implementation.
-  virtual void RunMenu(views::View* source, const gfx::Point& pt);
-
-  DISALLOW_COPY_AND_ASSIGN(WindowSwitcherButton);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_STATUS_WINDOW_SWITCHER_BUTTON_H_
diff --git a/chrome/browser/chromeos/view_ids.h b/chrome/browser/chromeos/view_ids.h
index 090490e..6d31565 100644
--- a/chrome/browser/chromeos/view_ids.h
+++ b/chrome/browser/chromeos/view_ids.h
@@ -15,6 +15,7 @@
   VIEW_ID_STATUS_AREA = VIEW_ID_PREDEFINED_COUNT + 10000,
   VIEW_ID_SCREEN_LOCKER_SIGNOUT_LINK,
   VIEW_ID_SCREEN_LOCKER_SHUTDOWN,
+  VIEW_ID_LAYOUT_MODE_BUTTON,
 };
 
 #endif  // CHROME_BROWSER_CHROMEOS_VIEW_IDS_H_
diff --git a/chrome/browser/chromeos/wm_ipc.cc b/chrome/browser/chromeos/wm_ipc.cc
index 97e1e56..aad446c6 100644
--- a/chrome/browser/chromeos/wm_ipc.cc
+++ b/chrome/browser/chromeos/wm_ipc.cc
@@ -12,6 +12,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "content/common/notification_service.h"
 #include "ui/base/x/x11_util.h"
 
 using std::map;
@@ -30,6 +31,7 @@
 
 // Each value from the Atom enum must be present here.
 static const AtomInfo kAtomInfos[] = {
+  { WmIpc::ATOM_CHROME_LAYOUT_MODE,           "_CHROME_LAYOUT_MODE" },
   { WmIpc::ATOM_CHROME_LOGGED_IN,             "_CHROME_LOGGED_IN" },
   { WmIpc::ATOM_CHROME_STATE,                 "_CHROME_STATE" },
   { WmIpc::ATOM_CHROME_STATE_COLLAPSED_PANEL, "_CHROME_STATE_COLLAPSED_PANEL" },
@@ -200,6 +202,14 @@
   }
 }
 
+void WmIpc::HandleRootWindowPropertyEvent(const GdkEventProperty& event) {
+  static GdkAtom layout_mode_gdk_atom =
+      gdk_x11_xatom_to_atom(type_to_atom_[ATOM_CHROME_LAYOUT_MODE]);
+
+  if (event.atom == layout_mode_gdk_atom)
+    FetchLayoutModeProperty();
+}
+
 void WmIpc::SetLoggedInProperty(bool logged_in) {
   std::vector<int> values;
   values.push_back(static_cast<int>(logged_in));
@@ -214,7 +224,10 @@
   XFlush(ui::GetXDisplay());
 }
 
-WmIpc::WmIpc() {
+WmIpc::WmIpc()
+    : wm_message_atom_(0),
+      wm_(0),
+      layout_mode_(WM_IPC_LAYOUT_MAXIMIZED) {
   scoped_array<char*> names(new char*[kNumAtoms]);
   scoped_array<Atom> atoms(new Atom[kNumAtoms]);
 
@@ -241,9 +254,12 @@
   GdkWindow* root = gdk_get_default_root_window();
   GdkEventMask event_mask = gdk_window_get_events(root);
   gdk_window_set_events(
-      root, static_cast<GdkEventMask>(event_mask | GDK_STRUCTURE_MASK));
+      root,
+      static_cast<GdkEventMask>(
+          event_mask | GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK));
 
   InitWmInfo();
+  FetchLayoutModeProperty();
 }
 
 WmIpc::~WmIpc() {}
@@ -260,4 +276,20 @@
   SendMessage(msg);
 }
 
+void WmIpc::FetchLayoutModeProperty() {
+  int value = 0;
+  if (ui::GetIntProperty(
+          gdk_x11_get_default_root_xwindow(),
+          GetAtomName(ATOM_CHROME_LAYOUT_MODE),
+          &value)) {
+    layout_mode_ = static_cast<WmIpcLayoutMode>(value);
+    NotificationService::current()->Notify(
+        NotificationType::LAYOUT_MODE_CHANGED,
+        Source<WmIpc>(this),
+        Details<WmIpcLayoutMode>(&layout_mode_));
+  } else {
+    DLOG(WARNING) << "Missing _CHROME_LAYOUT_MODE property on root window";
+  }
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/wm_ipc.h b/chrome/browser/chromeos/wm_ipc.h
index cb08351..152323b8 100644
--- a/chrome/browser/chromeos/wm_ipc.h
+++ b/chrome/browser/chromeos/wm_ipc.h
@@ -27,7 +27,8 @@
 class WmIpc {
  public:
   enum AtomType {
-    ATOM_CHROME_LOGGED_IN = 0,
+    ATOM_CHROME_LAYOUT_MODE = 0,
+    ATOM_CHROME_LOGGED_IN,
     ATOM_CHROME_STATE,
     ATOM_CHROME_STATE_COLLAPSED_PANEL,
     ATOM_CHROME_STATE_STATUS_HIDDEN,
@@ -88,6 +89,8 @@
   // Returns the single instance of WmIpc.
   static WmIpc* instance();
 
+  WmIpcLayoutMode layout_mode() const { return layout_mode_; }
+
   // Gets or sets a property describing a window's type.
   // WmIpcMessageType is defined in chromeos_wm_ipc_enums.h.  Type-specific
   // parameters may also be supplied.  The caller is responsible for trapping
@@ -122,6 +125,9 @@
   // See ICCCM 2.8 for more info about MANAGER selections.
   void HandleNonChromeClientMessageEvent(const GdkEventClient& event);
 
+  // Handle an event reporting a property change on the root window.
+  void HandleRootWindowPropertyEvent(const GdkEventProperty& event);
+
   // Sets a _CHROME_LOGGED_IN property on the root window describing whether
   // the user is currently logged in or not.
   void SetLoggedInProperty(bool logged_in);
@@ -135,11 +141,15 @@
   WmIpc();
   ~WmIpc();
 
-  // Initialize 'wm_' and send the window manager a message telling it the
+  // Initializes 'wm_' and sends the window manager a message telling it the
   // version of the IPC protocol that we support.  This is called in our
   // constructor, but needs to be re-run if the window manager gets restarted.
   void InitWmInfo();
 
+  // Updates |layout_mode_| based on the current value of the root window's
+  // _CHROME_LAYOUT_MODE property.
+  void FetchLayoutModeProperty();
+
   // Maps between our Atom enum and the X server's atom IDs and from the
   // server's IDs to atoms' string names.
   std::map<AtomType, Atom> type_to_atom_;
@@ -149,9 +159,12 @@
   // Cached value of type_to_atom_[ATOM_CHROME_WM_MESSAGE].
   Atom wm_message_atom_;
 
-  // Handle to the wm. Used for sending messages.
+  // Handle to the WM. Used for sending messages.
   XID wm_;
 
+  // The current value of the root window's _CHROME_LAYOUT_MODE property.
+  WmIpcLayoutMode layout_mode_;
+
   DISALLOW_COPY_AND_ASSIGN(WmIpc);
 };
 
diff --git a/chrome/browser/chromeos/wm_message_listener.cc b/chrome/browser/chromeos/wm_message_listener.cc
index c0815e4..aa493a3 100644
--- a/chrome/browser/chromeos/wm_message_listener.cc
+++ b/chrome/browser/chromeos/wm_message_listener.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
 
@@ -28,6 +28,11 @@
       ProcessMessage(message, client_event->window);
     else
       wm_ipc->HandleNonChromeClientMessageEvent(*client_event);
+  } else if (event->type == GDK_PROPERTY_NOTIFY) {
+    GdkEventProperty* property_event =
+        reinterpret_cast<GdkEventProperty*>(event);
+    if (property_event->window == gdk_get_default_root_window())
+      WmIpc::instance()->HandleRootWindowPropertyEvent(*property_event);
   }
 }
 
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 2964ee9..435c88b3 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -413,6 +413,8 @@
         'browser/chromeos/frame/bubble_frame_view.h',
         'browser/chromeos/frame/bubble_window.cc',
         'browser/chromeos/frame/bubble_window.h',
+        'browser/chromeos/frame/layout_mode_button.cc',
+        'browser/chromeos/frame/layout_mode_button.h',
         'browser/chromeos/frame/panel_browser_view.cc',
         'browser/chromeos/frame/panel_browser_view.h',
         'browser/chromeos/frame/panel_controller.cc',
@@ -699,8 +701,6 @@
         'browser/chromeos/status/status_area_host.h',
         'browser/chromeos/status/status_area_view.cc',
         'browser/chromeos/status/status_area_view.h',
-        'browser/chromeos/status/window_switcher_button.cc',
-        'browser/chromeos/status/window_switcher_button.h',
         'browser/chromeos/system_access.cc',
         'browser/chromeos/system_access.h',
         'browser/chromeos/system_key_event_listener.cc',
diff --git a/content/common/notification_type.h b/content/common/notification_type.h
index 418df4ec..c51f947c 100644
--- a/content/common/notification_type.h
+++ b/content/common/notification_type.h
@@ -1228,6 +1228,9 @@
     // Sent when a panel state changed.
     PANEL_STATE_CHANGED,
 
+    // Sent when the window manager's layout mode has changed.
+    LAYOUT_MODE_CHANGED,
+
     // Sent when the wizard's content view is destroyed. The source and details
     // are not used.
     WIZARD_CONTENT_VIEW_DESTROYED,