summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-14 02:27:50 +0000
committerpkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-14 02:27:50 +0000
commit97decb5726a169fe67a70e1a3842ee7c6d331e18 (patch)
treeb20a676eb6a906e7308b5363d3fed7f13d01a606
parente49c390d04cc09b4d37811af741e6029e45d0db7 (diff)
downloadchromium_src-97decb5726a169fe67a70e1a3842ee7c6d331e18.zip
chromium_src-97decb5726a169fe67a70e1a3842ee7c6d331e18.tar.gz
chromium_src-97decb5726a169fe67a70e1a3842ee7c6d331e18.tar.bz2
1) Fix repaint glitches wrt to the solo window header when window docking is enabled. The glitches were occurring because windows move to the kShellWindowId_DockedContainer for the duration of a drag and windows were not properly repainted
2) Change the behavior of the solo header such that: - Docked windows never use the solo window header - Windows which are not docked cannot use the solo window header when there is a docked window (There must be exactly one window onscreen in order to use the solo window header) - A window can use the solo window header when it is being dragged even though it is in the kShellWindowId_DockedContainer BUG=317439 TEST=SoloWindowTrackerTest.DockedWindow R=jamescook TBR=sky (For trivial change to chrome/browser/chromeos/login/login_display_host_impl.cc) Review URL: https://codereview.chromium.org/68373002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@235020 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/ash.gyp3
-rw-r--r--ash/root_window_controller.cc15
-rw-r--r--ash/root_window_controller.h8
-rw-r--r--ash/root_window_settings.cc3
-rw-r--r--ash/root_window_settings.h4
-rw-r--r--ash/wm/header_painter.cc176
-rw-r--r--ash/wm/header_painter.h29
-rw-r--r--ash/wm/header_painter_unittest.cc488
-rw-r--r--ash/wm/solo_window_tracker.cc210
-rw-r--r--ash/wm/solo_window_tracker.h81
-rw-r--r--ash/wm/solo_window_tracker_unittest.cc423
-rw-r--r--ash/wm/workspace/workspace_layout_manager.cc2
-rw-r--r--chrome/browser/chromeos/login/login_display_host_impl.cc6
13 files changed, 748 insertions, 700 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 388b822..46213cf 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -518,6 +518,8 @@
'wm/screen_dimmer.h',
'wm/session_state_animator.cc',
'wm/session_state_animator.h',
+ 'wm/solo_window_tracker.cc',
+ 'wm/solo_window_tracker.h',
'wm/stacking_controller.cc',
'wm/stacking_controller.h',
'wm/status_area_layout_manager.cc',
@@ -829,6 +831,7 @@
'wm/partial_screenshot_view_unittest.cc',
'wm/resize_shadow_and_cursor_unittest.cc',
'wm/screen_dimmer_unittest.cc',
+ 'wm/solo_window_tracker_unittest.cc',
'wm/stacking_controller_unittest.cc',
'wm/sticky_keys_unittest.cc',
'wm/system_gesture_event_filter_unittest.cc',
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index d66f169..de8c327 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -36,6 +36,7 @@
#include "ash/wm/panels/panel_window_event_handler.h"
#include "ash/wm/root_window_layout_manager.h"
#include "ash/wm/screen_dimmer.h"
+#include "ash/wm/solo_window_tracker.h"
#include "ash/wm/stacking_controller.h"
#include "ash/wm/status_area_layout_manager.h"
#include "ash/wm/system_background_controller.h"
@@ -396,6 +397,13 @@ void RootWindowController::OnWallpaperAnimationFinished(views::Widget* widget) {
void RootWindowController::CloseChildWindows() {
mouse_event_target_.reset();
+ // |solo_window_tracker_| must be shut down before windows are destroyed.
+ if (solo_window_tracker_) {
+ if (docked_layout_manager_)
+ docked_layout_manager_->RemoveObserver(solo_window_tracker_.get());
+ solo_window_tracker_.reset();
+ }
+
// Deactivate keyboard container before closing child windows and shutting
// down associated layout managers.
DeactivateKeyboard(Shell::GetInstance()->keyboard_controller());
@@ -563,7 +571,6 @@ void RootWindowController::DeactivateKeyboard(
}
}
-
////////////////////////////////////////////////////////////////////////////////
// RootWindowController, private:
@@ -617,10 +624,14 @@ void RootWindowController::Init(RootWindowType root_window_type,
root_window_->window());
root_window_->ShowRootWindow();
- // Create a launcher if a user is already logged.
+ // Create a launcher if a user is already logged in.
if (shell->session_state_delegate()->NumberOfLoggedInUsers())
shelf()->CreateLauncher();
}
+
+ solo_window_tracker_.reset(new SoloWindowTracker(root_window_.get()));
+ if (docked_layout_manager_)
+ docked_layout_manager_->AddObserver(solo_window_tracker_.get());
}
void RootWindowController::InitLayoutManagers() {
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 606cc50..076bfe6 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -43,8 +43,9 @@ class KeyboardController;
}
namespace ash {
-class StackingController;
class ShelfWidget;
+class SoloWindowTracker;
+class StackingController;
class SystemTray;
class ToplevelWindowEventHandler;
@@ -150,6 +151,10 @@ class ASH_EXPORT RootWindowController : public ShellObserver {
}
void SetAnimatingWallpaperController(AnimatingDesktopController* controller);
+ SoloWindowTracker* solo_window_tracker() {
+ return solo_window_tracker_.get();
+ }
+
// Access the shelf layout manager associated with this root
// window controller, NULL if no such shelf exists.
ShelfLayoutManager* GetShelfLayoutManager();
@@ -306,6 +311,7 @@ class ASH_EXPORT RootWindowController : public ShellObserver {
scoped_ptr<DesktopBackgroundWidgetController> wallpaper_controller_;
scoped_ptr<AnimatingDesktopController> animating_wallpaper_controller_;
scoped_ptr<views::corewm::ScopedCaptureClient> capture_client_;
+ scoped_ptr<SoloWindowTracker> solo_window_tracker_;
DISALLOW_COPY_AND_ASSIGN(RootWindowController);
};
diff --git a/ash/root_window_settings.cc b/ash/root_window_settings.cc
index 33880ed..b6e3b91 100644
--- a/ash/root_window_settings.cc
+++ b/ash/root_window_settings.cc
@@ -17,8 +17,7 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(RootWindowSettings,
kRootWindowSettingsKey, NULL);
RootWindowSettings::RootWindowSettings()
- : solo_window_header(false),
- display_id(gfx::Display::kInvalidDisplayID),
+ : display_id(gfx::Display::kInvalidDisplayID),
controller(NULL) {
}
diff --git a/ash/root_window_settings.h b/ash/root_window_settings.h
index e49b0f2..f187949 100644
--- a/ash/root_window_settings.h
+++ b/ash/root_window_settings.h
@@ -23,10 +23,6 @@ class RootWindowController;
struct RootWindowSettings {
RootWindowSettings();
- // Indicate if the window in the active workspace should
- // use the transparent "solo-window" header style.
- bool solo_window_header;
-
// ID of the display associated with the root window.
int64 display_id;
diff --git a/ash/wm/header_painter.cc b/ash/wm/header_painter.cc
index 3f8f2fe..fb0b2c4 100644
--- a/ash/wm/header_painter.cc
+++ b/ash/wm/header_painter.cc
@@ -6,25 +6,18 @@
#include <vector>
-#include "ash/ash_constants.h"
#include "ash/root_window_controller.h"
-#include "ash/root_window_settings.h"
-#include "ash/shell.h"
-#include "ash/shell_window_ids.h"
#include "ash/wm/caption_buttons/frame_caption_button_container_view.h"
+#include "ash/wm/solo_window_tracker.h"
#include "ash/wm/window_state.h"
-#include "ash/wm/window_util.h"
#include "base/logging.h" // DCHECK
#include "grit/ash_resources.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
-#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/animation/slide_animation.h"
@@ -36,7 +29,6 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
-using aura::RootWindow;
using aura::Window;
using views::Widget;
@@ -71,9 +63,6 @@ const int kActivationCrossfadeDurationMs = 200;
// Alpha/opacity value for fully-opaque headers.
const int kFullyOpaque = 255;
-// A flag to enable/disable solo window header.
-bool solo_window_header_enabled = true;
-
// Tiles an image into an area, rounding the top corners. Samples |image|
// starting |image_inset_x| pixels from the left of the image.
void TileRoundRect(gfx::Canvas* canvas,
@@ -143,53 +132,6 @@ void PaintFrameImagesInRoundRect(gfx::Canvas* canvas,
}
}
-// Returns true if |child| and all ancestors are visible. Useful to ensure that
-// a window is individually visible and is not part of a hidden workspace.
-bool IsVisibleToRoot(Window* child) {
- for (Window* window = child; window; window = window->parent()) {
- // We must use TargetVisibility() because windows animate in and out and
- // IsVisible() also tracks the layer visibility state.
- if (!window->TargetVisibility())
- return false;
- }
- return true;
-}
-
-// Returns true if |window| is a "normal" window for purposes of solo window
-// computations. Returns false for windows that are:
-// * Not drawn (for example, DragDropTracker uses one for mouse capture)
-// * Modal alerts (it looks odd for headers to change when an alert opens)
-// * Constrained windows (ditto)
-bool IsSoloWindowHeaderCandidate(aura::Window* window) {
- return window &&
- window->type() == aura::client::WINDOW_TYPE_NORMAL &&
- window->layer() &&
- window->layer()->type() != ui::LAYER_NOT_DRAWN &&
- window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE &&
- !window->GetProperty(ash::kConstrainedWindowKey);
-}
-
-// Returns a list of windows in |root_window|| that potentially could have
-// a transparent solo-window header.
-std::vector<Window*> GetWindowsForSoloHeaderUpdate(Window* root_window) {
- std::vector<Window*> windows;
- // Avoid memory allocations for typical window counts.
- windows.reserve(16);
- // Collect windows from the desktop.
- Window* desktop = ash::Shell::GetContainer(
- root_window, ash::internal::kShellWindowId_DefaultContainer);
- windows.insert(windows.end(),
- desktop->children().begin(),
- desktop->children().end());
- // Collect "always on top" windows.
- Window* top_container =
- ash::Shell::GetContainer(
- root_window, ash::internal::kShellWindowId_AlwaysOnTopContainer);
- windows.insert(windows.end(),
- top_container->children().begin(),
- top_container->children().end());
- return windows;
-}
} // namespace
namespace ash {
@@ -268,18 +210,6 @@ void HeaderPainter::Init(
}
// static
-void HeaderPainter::SetSoloWindowHeadersEnabled(bool enabled) {
- solo_window_header_enabled = enabled;
-}
-
-// static
-void HeaderPainter::UpdateSoloWindowHeader(Window* root_window) {
- // Use a separate function here so callers outside of HeaderPainter don't need
- // to know about "ignorable_window".
- UpdateSoloWindowInRoot(root_window, NULL /* ignorable_window */);
-}
-
-// static
gfx::Rect HeaderPainter::GetBoundsForClientView(
int header_height,
const gfx::Rect& window_bounds) {
@@ -571,17 +501,6 @@ void HeaderPainter::OnTrackedByWorkspaceChanged(wm::WindowState* window_state,
///////////////////////////////////////////////////////////////////////////////
// aura::WindowObserver overrides:
-void HeaderPainter::OnWindowVisibilityChanged(aura::Window* window,
- bool visible) {
- // OnWindowVisibilityChanged can be called for the child windows of |window_|.
- if (window != window_)
- return;
-
- // Window visibility change may trigger the change of window solo-ness in a
- // different window.
- UpdateSoloWindowInRoot(window_->GetRootWindow(), visible ? NULL : window_);
-}
-
void HeaderPainter::OnWindowDestroying(aura::Window* destroying) {
DCHECK_EQ(window_, destroying);
@@ -590,10 +509,6 @@ void HeaderPainter::OnWindowDestroying(aura::Window* destroying) {
window_->RemoveObserver(this);
wm::GetWindowState(window_)->RemoveObserver(this);
- // If we have two or more windows open and we close this one, we might trigger
- // the solo window appearance for another window.
- UpdateSoloWindowInRoot(window_->GetRootWindow(), window_);
-
window_ = NULL;
}
@@ -609,19 +524,6 @@ void HeaderPainter::OnWindowBoundsChanged(aura::Window* window,
}
}
-void HeaderPainter::OnWindowAddedToRootWindow(aura::Window* window) {
- // Needs to trigger the window appearance change if the window moves across
- // root windows and a solo window is already in the new root.
- UpdateSoloWindowInRoot(window->GetRootWindow(), NULL /* ignore_window */);
-}
-
-void HeaderPainter::OnWindowRemovingFromRootWindow(aura::Window* window) {
- // Needs to trigger the window appearance change if the window moves across
- // root windows and only one window is left in the previous root. Because
- // |window| is not yet moved, |window| has to be ignored.
- UpdateSoloWindowInRoot(window->GetRootWindow(), window);
-}
-
///////////////////////////////////////////////////////////////////////////////
// gfx::AnimationDelegate overrides:
@@ -673,9 +575,13 @@ int HeaderPainter::GetHeaderOpacity(
if (ShouldUseMinimalHeaderStyle(THEMED_NO))
return kFullyOpaque;
- // Single browser window is very transparent.
- if (UseSoloWindowHeader())
+ // Solo header is very transparent.
+ ash::SoloWindowTracker* solo_window_tracker =
+ internal::RootWindowController::ForWindow(window_)->solo_window_tracker();
+ if (solo_window_tracker &&
+ solo_window_tracker->GetWindowWithSoloHeader() == window_) {
return kSoloWindowOpacity;
+ }
// Otherwise, change transparency based on window activation status.
if (header_mode == ACTIVE)
@@ -683,74 +589,6 @@ int HeaderPainter::GetHeaderOpacity(
return kInactiveWindowOpacity;
}
-bool HeaderPainter::UseSoloWindowHeader() const {
- if (!solo_window_header_enabled)
- return false;
- // Don't use transparent headers for panels, pop-ups, etc.
- if (!IsSoloWindowHeaderCandidate(window_))
- return false;
- aura::Window* root = window_->GetRootWindow();
- // Don't recompute every time, as it would require many window property
- // lookups.
- return internal::GetRootWindowSettings(root)->solo_window_header;
-}
-
-// static
-bool HeaderPainter::UseSoloWindowHeaderInRoot(Window* root_window,
- Window* ignore_window) {
- int visible_window_count = 0;
- std::vector<Window*> windows = GetWindowsForSoloHeaderUpdate(root_window);
- for (std::vector<Window*>::const_iterator it = windows.begin();
- it != windows.end();
- ++it) {
- Window* window = *it;
- // Various sorts of windows "don't count" for this computation.
- if (ignore_window == window ||
- !IsSoloWindowHeaderCandidate(window) ||
- !IsVisibleToRoot(window))
- continue;
- if (wm::GetWindowState(window)->IsMaximized())
- return false;
- ++visible_window_count;
- if (visible_window_count > 1)
- return false;
- }
- // Count must be tested because all windows might be "don't count" windows
- // in the loop above.
- return visible_window_count == 1;
-}
-
-// static
-void HeaderPainter::UpdateSoloWindowInRoot(Window* root,
- Window* ignore_window) {
-#if defined(OS_WIN)
- // Non-Ash Windows doesn't do solo-window counting for transparency effects,
- // as the desktop background and window frames are managed by the OS.
- if (!ash::Shell::HasInstance())
- return;
-#endif
- if (!root)
- return;
- internal::RootWindowSettings* root_window_settings =
- internal::GetRootWindowSettings(root);
- bool old_solo_header = root_window_settings->solo_window_header;
- bool new_solo_header = UseSoloWindowHeaderInRoot(root, ignore_window);
- if (old_solo_header == new_solo_header)
- return;
- root_window_settings->solo_window_header = new_solo_header;
-
- // Invalidate all the window frames in the desktop. There should only be
- // a few.
- std::vector<Window*> windows = GetWindowsForSoloHeaderUpdate(root);
- for (std::vector<Window*>::const_iterator it = windows.begin();
- it != windows.end();
- ++it) {
- Widget* widget = Widget::GetWidgetForNativeWindow(*it);
- if (widget && widget->non_client_view())
- widget->non_client_view()->SchedulePaint();
- }
-}
-
void HeaderPainter::SchedulePaintForHeader() {
int top_left_height = top_left_corner_->height();
int top_right_height = top_right_corner_->height();
diff --git a/ash/wm/header_painter.h b/ash/wm/header_painter.h
index bdc5dbf7..ea326af 100644
--- a/ash/wm/header_painter.h
+++ b/ash/wm/header_painter.h
@@ -63,13 +63,6 @@ class ASH_EXPORT HeaderPainter : public aura::WindowObserver,
views::View* window_icon,
FrameCaptionButtonContainerView* caption_button_container);
- // Enable/Disable the solo-window transparent header appearance feature.
- static void SetSoloWindowHeadersEnabled(bool enabled);
-
- // Updates the solo-window transparent header appearance for all windows
- // using frame painters in |root_window|.
- static void UpdateSoloWindowHeader(aura::Window* root_window);
-
// Returns the bounds of the client view for a window with |header_height|
// and |window_bounds|. The return value and |window_bounds| are in the
// views::NonClientView's coordinates.
@@ -138,14 +131,10 @@ class ASH_EXPORT HeaderPainter : public aura::WindowObserver,
void OnThemeChanged();
// aura::WindowObserver overrides:
- virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) OVERRIDE;
virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
virtual void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) OVERRIDE;
- virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE;
- virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE;
// ash::WindowStateObserver override:
virtual void OnTrackedByWorkspaceChanged(wm::WindowState* window_state,
@@ -190,24 +179,6 @@ class ASH_EXPORT HeaderPainter : public aura::WindowObserver,
// Returns the radius of the header's top corners.
int GetHeaderCornerRadius() const;
- // Returns true if |window_->GetRootWindow()| should be drawing transparent
- // window headers.
- bool UseSoloWindowHeader() const;
-
- // Returns true if |root_window| has exactly one visible, normal-type window.
- // It ignores |ignore_window| while calculating the number of windows.
- // Pass NULL for |ignore_window| to consider all windows.
- static bool UseSoloWindowHeaderInRoot(aura::Window* root_window,
- aura::Window* ignore_window);
-
- // Updates the solo-window transparent header appearance for all windows in
- // |root_window|. If |ignore_window| is not NULL it is ignored for when
- // counting visible windows. This is useful for updates when a window is about
- // to be closed or is moving to another root. If the solo window status
- // changes it schedules paints as necessary.
- static void UpdateSoloWindowInRoot(aura::Window* root_window,
- aura::Window* ignore_window);
-
// Schedules a paint for the header. Used when transitioning from no header to
// a header (or other way around).
void SchedulePaintForHeader();
diff --git a/ash/wm/header_painter_unittest.cc b/ash/wm/header_painter_unittest.cc
index 55f0ff7..551658a 100644
--- a/ash/wm/header_painter_unittest.cc
+++ b/ash/wm/header_painter_unittest.cc
@@ -4,28 +4,14 @@
#include "ash/wm/header_painter.h"
-#include "ash/ash_constants.h"
-#include "ash/root_window_settings.h"
#include "ash/shell.h"
-#include "ash/shell_window_ids.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/caption_buttons/frame_caption_button_container_view.h"
#include "ash/wm/window_state.h"
-#include "ash/wm/window_util.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "grit/ash_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/base/hit_test.h"
#include "ui/gfx/font.h"
-#include "ui/gfx/screen.h"
#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/non_client_view.h"
using ash::HeaderPainter;
@@ -34,56 +20,6 @@ using views::Widget;
namespace {
-class ResizableWidgetDelegate : public views::WidgetDelegate {
- public:
- ResizableWidgetDelegate(views::Widget* widget) {
- widget_ = widget;
- }
-
- virtual bool CanResize() const OVERRIDE { return true; }
- // Implementations of the widget class.
- virtual views::Widget* GetWidget() OVERRIDE { return widget_; }
- virtual const views::Widget* GetWidget() const OVERRIDE { return widget_; }
- virtual void DeleteDelegate() OVERRIDE {
- delete this;
- }
-
- private:
- views::Widget* widget_;
-
- DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
-};
-
-class WindowRepaintChecker : public aura::WindowObserver {
- public:
- explicit WindowRepaintChecker(aura::Window* window)
- : is_paint_scheduled_(false) {
- window->AddObserver(this);
- }
- virtual ~WindowRepaintChecker() {
- }
-
- bool IsPaintScheduledAndReset() {
- bool result = is_paint_scheduled_;
- is_paint_scheduled_ = false;
- return result;
- }
-
- private:
- // aura::WindowObserver overrides:
- virtual void OnWindowPaintScheduled(aura::Window* window,
- const gfx::Rect& region) OVERRIDE {
- is_paint_scheduled_ = true;
- }
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
- window->RemoveObserver(this);
- }
-
- bool is_paint_scheduled_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker);
-};
-
// Modifies the values of kInactiveWindowOpacity, kActiveWindowOpacity, and
// kSoloWindowOpacity for the lifetime of the class. This is useful so that
// the constants each have different values.
@@ -129,33 +65,6 @@ HeaderPainter* CreateTestPainter(Widget* widget) {
return painter;
}
-// Self-owned manager of the frame painter which deletes the painter and itself
-// when its widget is closed.
-class HeaderPainterOwner : views::WidgetObserver {
- public:
- explicit HeaderPainterOwner(Widget* widget)
- : header_painter_(CreateTestPainter(widget)) {
- widget->AddObserver(this);
- }
-
- virtual ~HeaderPainterOwner() {}
-
- HeaderPainter* header_painter() { return header_painter_.get(); }
-
- private:
- virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
- widget->RemoveObserver(this);
- // Do not delete directly here, since the task of HeaderPainter causing
- // the crash of crbug.com/273310 may run after this class handles this
- // event.
- base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
- }
-
- scoped_ptr<HeaderPainter> header_painter_;
-
- DISALLOW_COPY_AND_ASSIGN(HeaderPainterOwner);
-};
-
} // namespace
namespace ash {
@@ -171,343 +80,8 @@ class HeaderPainterTest : public ash::test::AshTestBase {
widget->Init(params);
return widget;
}
-
- Widget* CreateAlwaysOnTopWidget() {
- Widget* widget = new Widget;
- Widget::InitParams params;
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.context = CurrentContext();
- params.keep_on_top = true;
- widget->Init(params);
- return widget;
- }
-
- Widget* CreatePanelWidget() {
- Widget* widget = new Widget;
- Widget::InitParams params;
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.context = CurrentContext();
- params.type = Widget::InitParams::TYPE_PANEL;
- widget->Init(params);
- return widget;
- }
-
- Widget* CreateResizableWidget() {
- Widget* widget = new Widget;
- Widget::InitParams params;
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.context = CurrentContext();
- params.keep_on_top = true;
- params.delegate = new ResizableWidgetDelegate(widget);
- params.type = Widget::InitParams::TYPE_WINDOW;
- widget->Init(params);
- return widget;
- }
};
-TEST_F(HeaderPainterTest, CreateAndDeleteSingleWindow) {
- // Ensure that creating/deleting a window works well and doesn't cause
- // crashes. See crbug.com/155634
- aura::Window* root = Shell::GetTargetRootWindow();
-
- scoped_ptr<Widget> widget(CreateTestWidget());
- scoped_ptr<HeaderPainter> painter(CreateTestPainter(widget.get()));
- widget->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(painter->UseSoloWindowHeader());
- EXPECT_TRUE(internal::GetRootWindowSettings(root)->solo_window_header);
-
- // Close the window.
- widget.reset();
- EXPECT_FALSE(internal::GetRootWindowSettings(root)->solo_window_header);
-
- // Recreate another window again.
- widget.reset(CreateTestWidget());
- painter.reset(CreateTestPainter(widget.get()));
- widget->Show();
- EXPECT_TRUE(painter->UseSoloWindowHeader());
- EXPECT_TRUE(internal::GetRootWindowSettings(root)->solo_window_header);
-}
-
-TEST_F(HeaderPainterTest, UseSoloWindowHeader) {
- // Create a widget and a painter for it.
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Create a second widget and painter.
- scoped_ptr<Widget> w2(CreateTestWidget());
- scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
- w2->Show();
-
- // Now there are two windows, so we should not use solo headers. This only
- // needs to test |p1| because "solo window headers" are a per-root-window
- // property.
- EXPECT_FALSE(p1->UseSoloWindowHeader());
-
- // Hide one window. Solo should be enabled.
- w2->Hide();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Show that window. Solo should be disabled.
- w2->Show();
- EXPECT_FALSE(p1->UseSoloWindowHeader());
-
- // Minimize the second window. Solo should be enabled.
- w2->Minimize();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Close the minimized window.
- w2.reset();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Open an always-on-top widget (which lives in a different container).
- scoped_ptr<Widget> w3(CreateAlwaysOnTopWidget());
- scoped_ptr<HeaderPainter> p3(CreateTestPainter(w3.get()));
- w3->Show();
- EXPECT_FALSE(p3->UseSoloWindowHeader());
-
- // Close the always-on-top widget.
- w3.reset();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-}
-
-// An open V2 app window should cause browser windows not to use the
-// solo window header.
-TEST_F(HeaderPainterTest, UseSoloWindowHeaderWithApp) {
- // Create a widget and a painter for it.
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Simulate a V2 app window, which is part of the active workspace but does
- // not have a frame painter.
- scoped_ptr<Widget> w2(CreateTestWidget());
- w2->Show();
-
- // Now there are two windows, so we should not use solo headers.
- EXPECT_FALSE(p1->UseSoloWindowHeader());
-
- // Minimize the app window. The first window should go solo again.
- w2->Minimize();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Restoring the app window turns off solo headers.
- w2->Restore();
- EXPECT_FALSE(p1->UseSoloWindowHeader());
-}
-
-// Panels should not "count" for computing solo window headers, and the panel
-// itself should always have an opaque header.
-TEST_F(HeaderPainterTest, UseSoloWindowHeaderWithPanel) {
- // Create a widget and a painter for it.
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Create a panel and a painter for it.
- scoped_ptr<Widget> w2(CreatePanelWidget());
- scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
- w2->Show();
-
- // Despite two windows, the first window should still be considered "solo"
- // because panels aren't included in the computation.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // The panel itself is not considered solo.
- EXPECT_FALSE(p2->UseSoloWindowHeader());
-
- // Even after closing the first window, the panel is still not considered
- // solo.
- w1.reset();
- EXPECT_FALSE(p2->UseSoloWindowHeader());
-}
-
-// Modal dialogs should not use solo headers.
-TEST_F(HeaderPainterTest, UseSoloWindowHeaderModal) {
- // Create a widget and a painter for it.
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Create a fake modal window.
- scoped_ptr<Widget> w2(CreateTestWidget());
- scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
- w2->GetNativeWindow()->SetProperty(aura::client::kModalKey,
- ui::MODAL_TYPE_WINDOW);
- w2->Show();
-
- // Despite two windows, the first window should still be considered "solo"
- // because modal windows aren't included in the computation.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // The modal window itself is not considered solo.
- EXPECT_FALSE(p2->UseSoloWindowHeader());
-}
-
-// Constrained windows should not use solo headers.
-TEST_F(HeaderPainterTest, UseSoloWindowHeaderConstrained) {
- // Create a widget and a painter for it.
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // Create a fake constrained window.
- scoped_ptr<Widget> w2(CreateTestWidget());
- scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
- w2->GetNativeWindow()->SetProperty(ash::kConstrainedWindowKey, true);
- w2->Show();
-
- // Despite two windows, the first window should still be considered "solo"
- // because constrained windows aren't included in the computation.
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- // The constrained window itself is not considered solo.
- EXPECT_FALSE(p2->UseSoloWindowHeader());
-}
-
-// Non-drawing windows should not affect the solo computation.
-TEST_F(HeaderPainterTest, UseSoloWindowHeaderNotDrawn) {
- // Create a widget and a painter for it.
- scoped_ptr<Widget> widget(CreateTestWidget());
- scoped_ptr<HeaderPainter> painter(CreateTestPainter(widget.get()));
- widget->Show();
-
- // We only have one window, so it should use a solo header.
- EXPECT_TRUE(painter->UseSoloWindowHeader());
-
- // Create non-drawing window similar to DragDropTracker.
- scoped_ptr<aura::Window> window(new aura::Window(NULL));
- window->SetType(aura::client::WINDOW_TYPE_NORMAL);
- window->Init(ui::LAYER_NOT_DRAWN);
- aura::client::ParentWindowWithContext(window.get(), widget->GetNativeWindow(),
- gfx::Rect());
- window->Show();
-
- // Despite two windows, the first window should still be considered "solo"
- // because non-drawing windows aren't included in the computation.
- EXPECT_TRUE(painter->UseSoloWindowHeader());
-}
-
-#if defined(OS_WIN)
-// Multiple displays are not supported on Windows Ash. http://crbug.com/165962
-#define MAYBE_UseSoloWindowHeaderMultiDisplay \
- DISABLED_UseSoloWindowHeaderMultiDisplay
-#else
-#define MAYBE_UseSoloWindowHeaderMultiDisplay \
- UseSoloWindowHeaderMultiDisplay
-#endif
-
-TEST_F(HeaderPainterTest, MAYBE_UseSoloWindowHeaderMultiDisplay) {
- if (!SupportsMultipleDisplays())
- return;
-
- UpdateDisplay("1000x600,600x400");
-
- // Create two widgets and painters for them.
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->Show();
- WindowRepaintChecker checker1(w1->GetNativeWindow());
- scoped_ptr<Widget> w2(CreateTestWidget());
- scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
- w2->SetBounds(gfx::Rect(0, 0, 100, 100));
- w2->Show();
- WindowRepaintChecker checker2(w2->GetNativeWindow());
-
- // Now there are two windows in the same display, so we should not use solo
- // headers.
- EXPECT_FALSE(p1->UseSoloWindowHeader());
- EXPECT_FALSE(p2->UseSoloWindowHeader());
- EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
-
- // Moves the second window to the secondary display. Both w1/w2 should be
- // solo.
- w2->SetBounds(gfx::Rect(1200, 0, 100, 100));
- EXPECT_TRUE(p1->UseSoloWindowHeader());
- EXPECT_TRUE(p2->UseSoloWindowHeader());
- EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
- EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
-
- // Open two more windows in the primary display.
- scoped_ptr<Widget> w3(CreateTestWidget());
- scoped_ptr<HeaderPainter> p3(CreateTestPainter(w3.get()));
- w3->SetBounds(gfx::Rect(0, 0, 100, 100));
- w3->Show();
- scoped_ptr<Widget> w4(CreateTestWidget());
- scoped_ptr<HeaderPainter> p4(CreateTestPainter(w4.get()));
- w4->SetBounds(gfx::Rect(0, 0, 100, 100));
- w4->Show();
-
- // Because the primary display has two windows w1 and w3, they shouldn't be
- // solo. w2 should be solo.
- EXPECT_FALSE(p1->UseSoloWindowHeader());
- EXPECT_TRUE(p2->UseSoloWindowHeader());
- EXPECT_FALSE(p3->UseSoloWindowHeader());
- EXPECT_FALSE(p4->UseSoloWindowHeader());
- EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
-
- // Moves the w4 to the secondary display. Now the w2 shouldn't be solo
- // anymore.
- w4->SetBounds(gfx::Rect(1200, 0, 100, 100));
- EXPECT_FALSE(p1->UseSoloWindowHeader());
- EXPECT_FALSE(p2->UseSoloWindowHeader());
- EXPECT_FALSE(p3->UseSoloWindowHeader());
- EXPECT_FALSE(p4->UseSoloWindowHeader());
- EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
-
- // Moves the w3 to the secondary display too. Now w1 should be solo again.
- w3->SetBounds(gfx::Rect(1200, 0, 100, 100));
- EXPECT_TRUE(p1->UseSoloWindowHeader());
- EXPECT_FALSE(p2->UseSoloWindowHeader());
- EXPECT_FALSE(p3->UseSoloWindowHeader());
- EXPECT_FALSE(p4->UseSoloWindowHeader());
- EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
-
- // Change the w3 state to maximize. Doesn't affect to w1.
- wm::GetWindowState(w3->GetNativeWindow())->Maximize();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
- EXPECT_FALSE(p2->UseSoloWindowHeader());
- EXPECT_FALSE(p3->UseSoloWindowHeader());
- EXPECT_FALSE(p4->UseSoloWindowHeader());
-
- // Close the w3 and w4.
- w3.reset();
- w4.reset();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
- EXPECT_TRUE(p2->UseSoloWindowHeader());
- EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
-
- // Move w2 back to the primary display.
- w2->SetBounds(gfx::Rect(0, 0, 100, 100));
- EXPECT_FALSE(p1->UseSoloWindowHeader());
- EXPECT_FALSE(p2->UseSoloWindowHeader());
- EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
- EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
-
- // Close w2.
- w2.reset();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
- EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
-}
-
TEST_F(HeaderPainterTest, GetHeaderOpacity) {
// Create a widget and a painter for it.
scoped_ptr<Widget> w1(CreateTestWidget());
@@ -601,66 +175,4 @@ TEST_F(HeaderPainterTest, TitleIconAlignment) {
short_header_title_bounds.CenterPoint().y());
}
-TEST_F(HeaderPainterTest, ChildWindowVisibility) {
- scoped_ptr<Widget> w1(CreateTestWidget());
- scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
- w1->Show();
-
- // Solo active window has solo window opacity.
- EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
- p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
- IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- 0));
-
- // Create a child window which doesn't affect the solo header.
- scoped_ptr<Widget> w2(new Widget);
- Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.parent = w1->GetNativeView();
- w2->Init(params);
- w2->Show();
-
- // Still has solo header if child window is added.
- EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
- p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
- IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- 0));
-
- // Change the visibility of w2 and verifies w1 still has solo header.
- w2->Hide();
- EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
- p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
- IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- 0));
-}
-
-TEST_F(HeaderPainterTest, NoCrashShutdownWithAlwaysOnTopWindow) {
- // Create normal window and an always-on-top window, and leave it as is
- // and finish the test, then verify it doesn't cause a crash. See
- // crbug.com/273310. Note that those widgets will be deleted at
- // RootWindowController::CloseChildWindows(), so this code is memory-safe.
- Widget* w1 = new Widget;
- Widget::InitParams params1;
- params1.context = CurrentContext();
- w1->Init(params1);
- HeaderPainterOwner* o1 = new HeaderPainterOwner(w1);
- HeaderPainter* p1 = o1->header_painter();
- w1->SetBounds(gfx::Rect(0, 0, 100, 100));
- w1->Show();
- EXPECT_TRUE(p1->UseSoloWindowHeader());
-
- Widget* w2 = new Widget;
- Widget::InitParams params2;
- params2.context = CurrentContext();
- params2.keep_on_top = true;
- w2->Init(params2);
- HeaderPainterOwner* o2 = new HeaderPainterOwner(w2);
- HeaderPainter* p2 = o2->header_painter();
- w2->Show();
- EXPECT_FALSE(p1->UseSoloWindowHeader());
- EXPECT_FALSE(p2->UseSoloWindowHeader());
-
- // Exit with no resource release. They'll be released at shutdown.
-}
-
} // namespace ash
diff --git a/ash/wm/solo_window_tracker.cc b/ash/wm/solo_window_tracker.cc
new file mode 100644
index 0000000..71299d2
--- /dev/null
+++ b/ash/wm/solo_window_tracker.cc
@@ -0,0 +1,210 @@
+// Copyright 2013 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 "ash/wm/solo_window_tracker.h"
+
+#include <algorithm>
+
+#include "ash/ash_constants.h"
+#include "ash/root_window_controller.h"
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/window_state_observer.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+
+namespace ash {
+
+namespace {
+
+// A flag to enable/disable the solo window header across all root windows.
+bool g_solo_header_enabled = true;
+
+// Returns the containers from which a solo window is chosen.
+std::vector<aura::Window*> GetContainers(aura::RootWindow* root_window) {
+ int kContainerIds[] = {
+ internal::kShellWindowId_DefaultContainer,
+ internal::kShellWindowId_AlwaysOnTopContainer,
+ // Docked windows never use the solo header, but regular windows move to the
+ // docked container when dragged.
+ internal::kShellWindowId_DockedContainer,
+ };
+ std::vector<aura::Window*> containers;
+ for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
+ containers.push_back(
+ Shell::GetContainer(root_window->window(), kContainerIds[i]));
+ }
+ return containers;
+}
+
+// Returns true if |child| and all of its ancestors are visible and neither
+// |child| nor any its ancestors is animating hidden.
+bool GetTargetVisibility(aura::Window* child) {
+ for (aura::Window* window = child; window; window = window->parent()) {
+ if (!window->TargetVisibility())
+ return false;
+ }
+ return true;
+}
+
+// Returns true if |window| can use the solo window header. Returns false for
+// windows that are:
+// * Not drawn (for example, DragDropTracker uses one for mouse capture)
+// * Modal alerts (it looks odd for headers to change when an alert opens)
+// * Constrained windows (ditto)
+bool IsValidCandidate(aura::Window* window) {
+ return window->type() == aura::client::WINDOW_TYPE_NORMAL &&
+ window->layer() &&
+ window->layer()->type() != ui::LAYER_NOT_DRAWN &&
+ window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE &&
+ !window->GetProperty(ash::kConstrainedWindowKey);
+}
+
+// Schedule's a paint of the window's entire bounds.
+void SchedulePaint(aura::Window* window) {
+ window->SchedulePaintInRect(gfx::Rect(window->bounds().size()));
+}
+
+} // namespace
+
+
+// Class which triggers a repaint of the window which is passed to the
+// constructor whenever the window's show type changes. The window's non client
+// view is responsible for updating whether it uses the solo header as part of
+// the repaint by querying GetWindowWithSoloHeader().
+class SoloWindowTracker::SoloWindowObserver
+ : public ash::wm::WindowStateObserver {
+ public:
+ explicit SoloWindowObserver(aura::Window* window) : window_(window) {
+ wm::GetWindowState(window_)->AddObserver(this);
+ }
+
+ virtual ~SoloWindowObserver() {
+ wm::GetWindowState(window_)->RemoveObserver(this);
+ }
+
+ private:
+ // ash::wm::WindowStateObserver override.
+ virtual void OnWindowShowTypeChanged(
+ ash::wm::WindowState* window_state,
+ ash::wm::WindowShowType old_type) OVERRIDE {
+ SchedulePaint(window_);
+ }
+
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoloWindowObserver);
+};
+
+SoloWindowTracker::SoloWindowTracker(aura::RootWindow* root_window)
+ : containers_(GetContainers(root_window)),
+ solo_window_(NULL) {
+ for (size_t i = 0; i < containers_.size(); ++i)
+ containers_[i]->AddObserver(this);
+}
+
+SoloWindowTracker::~SoloWindowTracker() {
+ for (size_t i = 0; i < containers_.size(); ++i)
+ containers_[i]->RemoveObserver(this);
+}
+
+// static
+void SoloWindowTracker::SetSoloHeaderEnabled(bool enabled) {
+ g_solo_header_enabled = enabled;
+ std::vector<aura::Window*> root_windows =
+ Shell::GetInstance()->GetAllRootWindows();
+ for (size_t i = 0; i < root_windows.size(); ++i) {
+ SoloWindowTracker* tracker =
+ internal::GetRootWindowController(root_windows[i])->
+ solo_window_tracker();
+ if (tracker)
+ tracker->UpdateSoloWindow(NULL);
+ }
+}
+
+aura::Window* SoloWindowTracker::GetWindowWithSoloHeader() {
+ bool use_solo_header = solo_window_ &&
+ !wm::GetWindowState(solo_window_)->IsMaximizedOrFullscreen();
+ return use_solo_header ? solo_window_ : NULL;
+}
+
+void SoloWindowTracker::UpdateSoloWindow(aura::Window* ignore_window) {
+ std::vector<aura::Window*> candidates;
+ // Avoid memory allocations for typical window counts.
+ candidates.reserve(16);
+ for (size_t i = 0; i < containers_.size(); ++i) {
+ candidates.insert(candidates.end(),
+ containers_[i]->children().begin(),
+ containers_[i]->children().end());
+ }
+
+ aura::Window* old_solo_window = solo_window_;
+ solo_window_ = NULL;
+ if (g_solo_header_enabled && !AnyVisibleWindowDocked()) {
+ for (size_t i = 0; i < candidates.size(); ++i) {
+ aura::Window* candidate = candidates[i];
+ // Various sorts of windows "don't count" for this computation.
+ if (candidate == ignore_window ||
+ !IsValidCandidate(candidate) ||
+ !GetTargetVisibility(candidate)) {
+ continue;
+ }
+
+ if (solo_window_) {
+ // A window can only use the solo header if it is the only visible valid
+ // candidate (and there are no visible docked windows).
+ solo_window_ = NULL;
+ break;
+ } else {
+ solo_window_ = candidate;
+ }
+ }
+ }
+
+ if (solo_window_ == old_solo_window)
+ return;
+
+ solo_window_observer_.reset(solo_window_ ?
+ new SoloWindowObserver(solo_window_) : NULL);
+ if (old_solo_window)
+ SchedulePaint(old_solo_window);
+ if (solo_window_)
+ SchedulePaint(solo_window_);
+}
+
+bool SoloWindowTracker::AnyVisibleWindowDocked() const {
+ // For the purpose of SoloWindowTracker, there is a visible docked window if
+ // it causes the dock to have non-empty bounds. This is intentionally
+ // different from:
+ // DockedWindowLayoutManager::IsAnyWindowDocked() and
+ // DockedWindowLayoutManager::is_dragged_window_docked().
+ return !dock_bounds_.IsEmpty();
+}
+
+void SoloWindowTracker::OnWindowAdded(aura::Window* new_window) {
+ UpdateSoloWindow(NULL);
+}
+
+void SoloWindowTracker::OnWillRemoveWindow(aura::Window* window) {
+ UpdateSoloWindow(window);
+}
+
+void SoloWindowTracker::OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) {
+ // |window| may be a grandchild of |containers_|.
+ std::vector<aura::Window*>::const_iterator it = std::find(
+ containers_.begin(), containers_.end(), window->parent());
+ if (it != containers_.end())
+ UpdateSoloWindow(NULL);
+}
+
+void SoloWindowTracker::OnDockBoundsChanging(const gfx::Rect& new_bounds,
+ Reason reason) {
+ dock_bounds_ = new_bounds;
+ UpdateSoloWindow(NULL);
+}
+
+} // namespace ash
diff --git a/ash/wm/solo_window_tracker.h b/ash/wm/solo_window_tracker.h
new file mode 100644
index 0000000..829af01
--- /dev/null
+++ b/ash/wm/solo_window_tracker.h
@@ -0,0 +1,81 @@
+// Copyright 2013 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 ASH_WM_SOLO_WINDOW_TRACKER_H_
+#define ASH_WM_SOLO_WINDOW_TRACKER_H_
+
+#include <vector>
+
+#include "ash/ash_export.h"
+#include "ash/wm/dock/docked_window_layout_manager_observer.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_observer.h"
+#include "ui/gfx/rect.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+}
+
+namespace ash {
+
+// Class which keeps track of the window (if any) which should use the solo
+// window header. The solo window header is very transparent and is used when
+// there is only one visible window and the window is not maximized or
+// fullscreen. The solo window header is not used for either panels or docked
+// windows.
+class ASH_EXPORT SoloWindowTracker
+ : public aura::WindowObserver,
+ public internal::DockedWindowLayoutManagerObserver {
+ public:
+ explicit SoloWindowTracker(aura::RootWindow* root_window);
+ virtual ~SoloWindowTracker();
+
+ // Enable/Disable solo headers.
+ static void SetSoloHeaderEnabled(bool enabled);
+
+ // Returns the window, if any, which should use the solo window header.
+ aura::Window* GetWindowWithSoloHeader();
+
+ private:
+ // Updates the window which would use the solo header if the window were not
+ // maximized or fullscreen. If |ignore_window| is not NULL, it is ignored for
+ // counting valid candidates. This is useful when there is a window which is
+ // about to be moved to a different root window or about to be closed.
+ void UpdateSoloWindow(aura::Window* ignore_window);
+
+ // Returns true if there is a visible docked window.
+ bool AnyVisibleWindowDocked() const;
+
+ // aura::WindowObserver overrides:
+ virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE;
+ virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE;
+ virtual void OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) OVERRIDE;
+
+ // ash::internal::DockedWindowLayoutManagerObserver override:
+ virtual void OnDockBoundsChanging(const gfx::Rect& new_bounds,
+ Reason reason) OVERRIDE;
+
+ // The containers whose children can use the solo header.
+ std::vector<aura::Window*> containers_;
+
+ // The dock's bounds.
+ gfx::Rect dock_bounds_;
+
+ // The window which would use the solo header if it were not maximized or
+ // fullscreen.
+ aura::Window* solo_window_;
+
+ // Class which observes changes in |solo_window_|'s show type.
+ class SoloWindowObserver;
+ scoped_ptr<SoloWindowObserver> solo_window_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoloWindowTracker);
+};
+
+} // namespace ash
+
+#endif // ASH_WM_SOLO_WINDOW_TRACKER_H_
diff --git a/ash/wm/solo_window_tracker_unittest.cc b/ash/wm/solo_window_tracker_unittest.cc
new file mode 100644
index 0000000..f682fc8
--- /dev/null
+++ b/ash/wm/solo_window_tracker_unittest.cc
@@ -0,0 +1,423 @@
+// Copyright 2013 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 "ash/wm/solo_window_tracker.h"
+
+#include "ash/ash_constants.h"
+#include "ash/ash_switches.h"
+#include "ash/root_window_controller.h"
+#include "ash/screen_ash.h"
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/window_resizer.h"
+#include "ash/wm/window_state.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/hit_test.h"
+#include "ui/gfx/screen.h"
+
+namespace ash {
+
+namespace {
+
+class WindowRepaintChecker : public aura::WindowObserver {
+ public:
+ explicit WindowRepaintChecker(aura::Window* window)
+ : is_paint_scheduled_(false) {
+ window->AddObserver(this);
+ }
+ virtual ~WindowRepaintChecker() {
+ }
+
+ bool IsPaintScheduledAndReset() {
+ bool result = is_paint_scheduled_;
+ is_paint_scheduled_ = false;
+ return result;
+ }
+
+ private:
+ // aura::WindowObserver overrides:
+ virtual void OnWindowPaintScheduled(aura::Window* window,
+ const gfx::Rect& region) OVERRIDE {
+ is_paint_scheduled_ = true;
+ }
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
+ window->RemoveObserver(this);
+ }
+
+ bool is_paint_scheduled_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker);
+};
+
+} // namespace
+
+class SoloWindowTrackerTest : public test::AshTestBase {
+ public:
+ SoloWindowTrackerTest() {
+ }
+ virtual ~SoloWindowTrackerTest() {
+ }
+
+ // Helpers methods to create test windows in the primary root window.
+ aura::Window* CreateWindowInPrimary() {
+ aura::Window* window = new aura::Window(NULL);
+ window->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ window->Init(ui::LAYER_TEXTURED);
+ window->SetBounds(gfx::Rect(100, 100));
+ ParentWindowInPrimaryRootWindow(window);
+ return window;
+ }
+ aura::Window* CreateAlwaysOnTopWindowInPrimary() {
+ aura::Window* window = new aura::Window(NULL);
+ window->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ window->Init(ui::LAYER_TEXTURED);
+ window->SetBounds(gfx::Rect(100, 100));
+ window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+ ParentWindowInPrimaryRootWindow(window);
+ return window;
+ }
+ aura::Window* CreatePanelWindowInPrimary() {
+ aura::Window* window = new aura::Window(NULL);
+ window->SetType(aura::client::WINDOW_TYPE_PANEL);
+ window->Init(ui::LAYER_TEXTURED);
+ window->SetBounds(gfx::Rect(100, 100));
+ ParentWindowInPrimaryRootWindow(window);
+ return window;
+ }
+
+ // Drag |window| to the dock.
+ void DockWindow(aura::Window* window) {
+ // Because the tests use windows without delegates,
+ // aura::test::EventGenerator cannot be used.
+ gfx::Point drag_to =
+ ash::ScreenAsh::GetDisplayBoundsInParent(window).top_right();
+ scoped_ptr<WindowResizer> resizer(CreateWindowResizer(
+ window,
+ window->bounds().origin(),
+ HTCAPTION,
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE));
+ resizer->Drag(drag_to, 0);
+ resizer->CompleteDrag(0);
+ EXPECT_EQ(internal::kShellWindowId_DockedContainer,
+ window->parent()->id());
+ }
+
+ // Drag |window| out of the dock.
+ void UndockWindow(aura::Window* window) {
+ gfx::Point drag_to =
+ ash::ScreenAsh::GetDisplayWorkAreaBoundsInParent(window).top_right() -
+ gfx::Vector2d(10, 0);
+ scoped_ptr<WindowResizer> resizer(CreateWindowResizer(
+ window,
+ window->bounds().origin(),
+ HTCAPTION,
+ aura::client::WINDOW_MOVE_SOURCE_MOUSE));
+ resizer->Drag(drag_to, 0);
+ resizer->CompleteDrag(0);
+ EXPECT_NE(internal::kShellWindowId_DockedContainer,
+ window->parent()->id());
+ }
+
+ // Returns the primary display.
+ gfx::Display GetPrimaryDisplay() {
+ return ash::Shell::GetInstance()->GetScreen()->GetPrimaryDisplay();
+ }
+
+ // Returns the secondary display.
+ gfx::Display GetSecondaryDisplay() {
+ return ScreenAsh::GetSecondaryDisplay();
+ }
+
+ // Returns the window which uses the solo header, if any, on the primary
+ // display.
+ aura::Window* GetWindowWithSoloHeaderInPrimary() {
+ return GetWindowWithSoloHeader(Shell::GetPrimaryRootWindow());
+ }
+
+ // Returns the window which uses the solo header, if any, in |root|.
+ aura::Window* GetWindowWithSoloHeader(aura::Window* root) {
+ SoloWindowTracker* solo_window_tracker =
+ internal::GetRootWindowController(root)->solo_window_tracker();
+ return solo_window_tracker ?
+ solo_window_tracker->GetWindowWithSoloHeader() : NULL;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SoloWindowTrackerTest);
+};
+
+TEST_F(SoloWindowTrackerTest, Basic) {
+ scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
+ w1->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Create a second window.
+ scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
+ w2->Show();
+
+ // Now there are two windows, so we should not use solo headers.
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ // Hide one window. Solo should be enabled.
+ w2->Hide();
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Show that window. Solo should be disabled.
+ w2->Show();
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ // Minimize the first window. Solo should be enabled.
+ wm::GetWindowState(w1.get())->Minimize();
+ EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Close the minimized window.
+ w1.reset();
+ EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Open an always-on-top window (which lives in a different container).
+ scoped_ptr<aura::Window> w3(CreateAlwaysOnTopWindowInPrimary());
+ w3->Show();
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ // Close the always-on-top window.
+ w3.reset();
+ EXPECT_EQ(w2.get(), GetWindowWithSoloHeaderInPrimary());
+}
+
+// Test that docked windows never use the solo header and that the presence of a
+// docked window prevents all other windows from the using the solo window
+// header.
+TEST_F(SoloWindowTrackerTest, DockedWindow) {
+ if (!switches::UseDockedWindows())
+ return;
+
+ scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
+ w1->Show();
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ DockWindow(w1.get());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ UndockWindow(w1.get());
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
+ w2->Show();
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ DockWindow(w2.get());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ wm::GetWindowState(w2.get())->Minimize();
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+}
+
+// Panels should not "count" for computing solo window headers, and the panel
+// itself should never use the solo header.
+TEST_F(SoloWindowTrackerTest, Panel) {
+ scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
+ w1->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Create a panel window.
+ scoped_ptr<aura::Window> w2(CreatePanelWindowInPrimary());
+ w2->Show();
+
+ // Despite two windows, the first window should still be considered "solo"
+ // because panels aren't included in the computation.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Even after closing the first window, the panel is still not considered
+ // solo.
+ w1.reset();
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+}
+
+// Modal dialogs should not use solo headers.
+TEST_F(SoloWindowTrackerTest, Modal) {
+ scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
+ w1->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Create a fake modal window.
+ scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
+ w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
+ w2->Show();
+
+ // Despite two windows, the first window should still be considered "solo"
+ // because modal windows aren't included in the computation.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+}
+
+// Constrained windows should not use solo headers.
+TEST_F(SoloWindowTrackerTest, Constrained) {
+ scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
+ w1->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Create a fake constrained window.
+ scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
+ w2->SetProperty(ash::kConstrainedWindowKey, true);
+ w2->Show();
+
+ // Despite two windows, the first window should still be considered "solo"
+ // because constrained windows aren't included in the computation.
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+}
+
+// Non-drawing windows should not affect the solo computation.
+TEST_F(SoloWindowTrackerTest, NotDrawn) {
+ aura::Window* w = CreateWindowInPrimary();
+ w->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
+
+ // Create non-drawing window similar to DragDropTracker.
+ aura::Window* not_drawn = new aura::Window(NULL);
+ not_drawn->SetType(aura::client::WINDOW_TYPE_NORMAL);
+ not_drawn->Init(ui::LAYER_NOT_DRAWN);
+ ParentWindowInPrimaryRootWindow(not_drawn);
+ not_drawn->Show();
+
+ // Despite two windows, the first window should still be considered "solo"
+ // because non-drawing windows aren't included in the computation.
+ EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
+}
+
+TEST_F(SoloWindowTrackerTest, MultiDisplay) {
+ if (!SupportsMultipleDisplays())
+ return;
+
+ UpdateDisplay("1000x600,600x400");
+
+ scoped_ptr<aura::Window> w1(CreateWindowInPrimary());
+ w1->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
+ w1->Show();
+ WindowRepaintChecker checker1(w1.get());
+ scoped_ptr<aura::Window> w2(CreateWindowInPrimary());
+ w2->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
+ w2->Show();
+ WindowRepaintChecker checker2(w2.get());
+
+ // Now there are two windows in the same display, so we should not use solo
+ // headers.
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+ EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
+
+ // Moves the second window to the secondary display. Both w1/w2 should be
+ // solo.
+ w2->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100),
+ ScreenAsh::GetSecondaryDisplay());
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+ EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
+ EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
+ EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
+
+ // Open two more windows in the primary display.
+ scoped_ptr<aura::Window> w3(CreateWindowInPrimary());
+ w3->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
+ w3->Show();
+ scoped_ptr<aura::Window> w4(CreateWindowInPrimary());
+ w4->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
+ w4->Show();
+
+ // Because the primary display has three windows w1, w3, and w4, they
+ // shouldn't be solo. w2 should be solo.
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+ EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
+ EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
+
+ // Move w4 to the secondary display. Now w2 shouldn't be solo anymore.
+ w4->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100), GetSecondaryDisplay());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
+ EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
+
+ // Moves w3 to the secondary display too. Now w1 should be solo again.
+ w3->SetBoundsInScreen(gfx::Rect(1200, 0, 100, 100), GetSecondaryDisplay());
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
+ EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
+
+ // Change w3's state to maximize. Doesn't affect w1.
+ wm::GetWindowState(w3.get())->Maximize();
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeader(w2->GetRootWindow()));
+
+ // Close w3 and w4.
+ w3.reset();
+ w4.reset();
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+ EXPECT_EQ(w2.get(), GetWindowWithSoloHeader(w2->GetRootWindow()));
+ EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
+
+ // Move w2 back to the primary display.
+ w2->SetBoundsInScreen(gfx::Rect(0, 0, 100, 100), GetPrimaryDisplay());
+ EXPECT_EQ(w1->GetRootWindow(), w2->GetRootWindow());
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+ EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
+ EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
+
+ // Close w2.
+ w2.reset();
+ EXPECT_EQ(w1.get(), GetWindowWithSoloHeaderInPrimary());
+ EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
+}
+
+TEST_F(SoloWindowTrackerTest, ChildWindowVisibility) {
+ aura::Window* w = CreateWindowInPrimary();
+ w->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
+
+ // Create a child window. This should not affect the solo-ness of |w1|.
+ aura::Window* child = new aura::Window(NULL);
+ child->SetType(aura::client::WINDOW_TYPE_CONTROL);
+ child->Init(ui::LAYER_TEXTURED);
+ child->SetBounds(gfx::Rect(100, 100));
+ w->AddChild(child);
+ child->Show();
+ EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
+
+ // Changing the visibility of |child| should not affect the solo-ness of |w1|.
+ child->Hide();
+ EXPECT_EQ(w, GetWindowWithSoloHeaderInPrimary());
+}
+
+TEST_F(SoloWindowTrackerTest, CreateAndDeleteSingleWindow) {
+ // Ensure that creating/deleting a window works well and doesn't cause
+ // crashes. See crbug.com/155634
+ scoped_ptr<aura::Window> w(CreateWindowInPrimary());
+ w->Show();
+
+ // We only have one window, so it should use a solo header.
+ EXPECT_EQ(w.get(), GetWindowWithSoloHeaderInPrimary());
+
+ // Close the window.
+ w.reset();
+ EXPECT_EQ(NULL, GetWindowWithSoloHeaderInPrimary());
+
+ // Recreate another window again.
+ w.reset(CreateWindowInPrimary());
+ w->Show();
+ EXPECT_EQ(w.get(), GetWindowWithSoloHeaderInPrimary());
+}
+
+} // namespace ash
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 513ea19..a0ae8cc 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -11,7 +11,6 @@
#include "ash/shell.h"
#include "ash/wm/always_on_top_controller.h"
#include "ash/wm/base_layout_manager.h"
-#include "ash/wm/header_painter.h"
#include "ash/wm/window_animations.h"
#include "ash/wm/window_positioner.h"
#include "ash/wm/window_properties.h"
@@ -289,7 +288,6 @@ void WorkspaceLayoutManager::AdjustWindowBoundsWhenAdded(
void WorkspaceLayoutManager::UpdateDesktopVisibility() {
if (shelf_)
shelf_->UpdateVisibilityState();
- HeaderPainter::UpdateSoloWindowHeader(window_->GetRootWindow());
}
void WorkspaceLayoutManager::UpdateBoundsFromShowState(
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc
index ed33875..173eebe 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/login_display_host_impl.cc
@@ -10,7 +10,7 @@
#include "ash/desktop_background/user_wallpaper_delegate.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
-#include "ash/wm/header_painter.h"
+#include "ash/wm/solo_window_tracker.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
@@ -932,7 +932,7 @@ void LoginDisplayHostImpl::StartPostponedWebUI() {
void LoginDisplayHostImpl::InitLoginWindowAndView() {
if (login_window_)
return;
- ash::HeaderPainter::SetSoloWindowHeadersEnabled(false);
+ ash::SoloWindowTracker::SetSoloHeaderEnabled(false);
if (system::keyboard_settings::ForceKeyboardDrivenUINavigation()) {
views::FocusManager::set_arrow_key_traversal_enabled(true);
@@ -986,7 +986,7 @@ void LoginDisplayHostImpl::InitLoginWindowAndView() {
void LoginDisplayHostImpl::ResetLoginWindowAndView() {
if (!login_window_)
return;
- ash::HeaderPainter::SetSoloWindowHeadersEnabled(true);
+ ash::SoloWindowTracker::SetSoloHeaderEnabled(true);
login_window_->Close();
login_window_ = NULL;
login_view_ = NULL;