1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/solo_window_tracker.h"
9 #include "ash/ash_constants.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/shell.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/wm/window_state.h"
14 #include "ash/wm/window_state_observer.h"
15 #include "ui/aura/client/aura_constants.h"
16 #include "ui/aura/root_window.h"
17 #include "ui/aura/window.h"
23 // A flag to enable/disable the solo window header across all root windows.
24 bool g_solo_header_enabled
= true;
26 // Returns the containers from which a solo window is chosen.
27 std::vector
<aura::Window
*> GetContainers(aura::RootWindow
* root_window
) {
28 int kContainerIds
[] = {
29 internal::kShellWindowId_DefaultContainer
,
30 internal::kShellWindowId_AlwaysOnTopContainer
,
31 // Docked windows never use the solo header, but regular windows move to the
32 // docked container when dragged.
33 internal::kShellWindowId_DockedContainer
,
35 std::vector
<aura::Window
*> containers
;
36 for (size_t i
= 0; i
< arraysize(kContainerIds
); ++i
) {
38 Shell::GetContainer(root_window
->window(), kContainerIds
[i
]));
43 // Returns true if |child| and all of its ancestors are visible and neither
44 // |child| nor any its ancestors is animating hidden.
45 bool GetTargetVisibility(aura::Window
* child
) {
46 for (aura::Window
* window
= child
; window
; window
= window
->parent()) {
47 if (!window
->TargetVisibility())
53 // Returns true if |window| can use the solo window header. Returns false for
55 // * Not drawn (for example, DragDropTracker uses one for mouse capture)
56 // * Modal alerts (it looks odd for headers to change when an alert opens)
57 // * Constrained windows (ditto)
58 bool IsValidCandidate(aura::Window
* window
) {
59 return window
->type() == aura::client::WINDOW_TYPE_NORMAL
&&
61 window
->layer()->type() != ui::LAYER_NOT_DRAWN
&&
62 window
->GetProperty(aura::client::kModalKey
) == ui::MODAL_TYPE_NONE
&&
63 !window
->GetProperty(ash::kConstrainedWindowKey
);
66 // Schedule's a paint of the window's entire bounds.
67 void SchedulePaint(aura::Window
* window
) {
68 window
->SchedulePaintInRect(gfx::Rect(window
->bounds().size()));
74 // Class which triggers a repaint of the window which is passed to the
75 // constructor whenever the window's show type changes. The window's non client
76 // view is responsible for updating whether it uses the solo header as part of
77 // the repaint by querying GetWindowWithSoloHeader().
78 class SoloWindowTracker::SoloWindowObserver
79 : public ash::wm::WindowStateObserver
{
81 explicit SoloWindowObserver(aura::Window
* window
) : window_(window
) {
82 wm::GetWindowState(window_
)->AddObserver(this);
85 virtual ~SoloWindowObserver() {
86 wm::GetWindowState(window_
)->RemoveObserver(this);
90 // ash::wm::WindowStateObserver override.
91 virtual void OnWindowShowTypeChanged(
92 ash::wm::WindowState
* window_state
,
93 ash::wm::WindowShowType old_type
) OVERRIDE
{
94 SchedulePaint(window_
);
97 aura::Window
* window_
;
99 DISALLOW_COPY_AND_ASSIGN(SoloWindowObserver
);
102 SoloWindowTracker::SoloWindowTracker(aura::RootWindow
* root_window
)
103 : containers_(GetContainers(root_window
)),
105 for (size_t i
= 0; i
< containers_
.size(); ++i
)
106 containers_
[i
]->AddObserver(this);
109 SoloWindowTracker::~SoloWindowTracker() {
110 for (size_t i
= 0; i
< containers_
.size(); ++i
)
111 containers_
[i
]->RemoveObserver(this);
115 void SoloWindowTracker::SetSoloHeaderEnabled(bool enabled
) {
116 g_solo_header_enabled
= enabled
;
117 std::vector
<aura::Window
*> root_windows
=
118 Shell::GetInstance()->GetAllRootWindows();
119 for (size_t i
= 0; i
< root_windows
.size(); ++i
) {
120 SoloWindowTracker
* tracker
=
121 internal::GetRootWindowController(root_windows
[i
])->
122 solo_window_tracker();
124 tracker
->UpdateSoloWindow(NULL
);
128 aura::Window
* SoloWindowTracker::GetWindowWithSoloHeader() {
129 bool use_solo_header
= solo_window_
&&
130 !wm::GetWindowState(solo_window_
)->IsMaximizedOrFullscreen();
131 return use_solo_header
? solo_window_
: NULL
;
134 void SoloWindowTracker::UpdateSoloWindow(aura::Window
* ignore_window
) {
135 std::vector
<aura::Window
*> candidates
;
136 // Avoid memory allocations for typical window counts.
137 candidates
.reserve(16);
138 for (size_t i
= 0; i
< containers_
.size(); ++i
) {
139 candidates
.insert(candidates
.end(),
140 containers_
[i
]->children().begin(),
141 containers_
[i
]->children().end());
144 aura::Window
* old_solo_window
= solo_window_
;
146 if (g_solo_header_enabled
&& !AnyVisibleWindowDocked()) {
147 for (size_t i
= 0; i
< candidates
.size(); ++i
) {
148 aura::Window
* candidate
= candidates
[i
];
149 // Various sorts of windows "don't count" for this computation.
150 if (candidate
== ignore_window
||
151 !IsValidCandidate(candidate
) ||
152 !GetTargetVisibility(candidate
)) {
157 // A window can only use the solo header if it is the only visible valid
158 // candidate (and there are no visible docked windows).
162 solo_window_
= candidate
;
167 if (solo_window_
== old_solo_window
)
170 solo_window_observer_
.reset(solo_window_
?
171 new SoloWindowObserver(solo_window_
) : NULL
);
173 SchedulePaint(old_solo_window
);
175 SchedulePaint(solo_window_
);
178 bool SoloWindowTracker::AnyVisibleWindowDocked() const {
179 // For the purpose of SoloWindowTracker, there is a visible docked window if
180 // it causes the dock to have non-empty bounds. This is intentionally
182 // DockedWindowLayoutManager::IsAnyWindowDocked() and
183 // DockedWindowLayoutManager::is_dragged_window_docked().
184 return !dock_bounds_
.IsEmpty();
187 void SoloWindowTracker::OnWindowAdded(aura::Window
* new_window
) {
188 UpdateSoloWindow(NULL
);
191 void SoloWindowTracker::OnWillRemoveWindow(aura::Window
* window
) {
192 UpdateSoloWindow(window
);
195 void SoloWindowTracker::OnWindowVisibilityChanged(aura::Window
* window
,
197 // |window| may be a grandchild of |containers_|.
198 std::vector
<aura::Window
*>::const_iterator it
= std::find(
199 containers_
.begin(), containers_
.end(), window
->parent());
200 if (it
!= containers_
.end())
201 UpdateSoloWindow(NULL
);
204 void SoloWindowTracker::OnDockBoundsChanging(const gfx::Rect
& new_bounds
,
206 dock_bounds_
= new_bounds
;
207 UpdateSoloWindow(NULL
);