OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "ash/wm/solo_window_tracker.h" | |
6 | |
7 #include <algorithm> | |
8 | |
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" | |
18 | |
19 namespace ash { | |
20 | |
21 namespace { | |
22 | |
23 // A flag to enable/disable the solo window header across all root windows. | |
24 bool g_solo_header_enabled = true; | |
25 | |
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, | |
34 }; | |
35 std::vector<aura::Window*> containers; | |
36 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { | |
37 containers.push_back( | |
38 Shell::GetContainer(root_window->window(), kContainerIds[i])); | |
39 } | |
40 return containers; | |
41 } | |
42 | |
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()) | |
48 return false; | |
49 } | |
50 return true; | |
51 } | |
52 | |
53 // Returns true if |window| can use the solo window header. Returns false for | |
54 // windows that are: | |
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() == ui::wm::WINDOW_TYPE_NORMAL && window->layer() && | |
60 window->layer()->type() != ui::LAYER_NOT_DRAWN && | |
61 window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE && | |
62 !window->GetProperty(aura::client::kConstrainedWindowKey); | |
63 } | |
64 | |
65 // Schedule's a paint of the window's entire bounds. | |
66 void SchedulePaint(aura::Window* window) { | |
67 window->SchedulePaintInRect(gfx::Rect(window->bounds().size())); | |
68 } | |
69 | |
70 } // namespace | |
71 | |
72 | |
73 // Class which triggers a repaint of the window which is passed to the | |
74 // constructor whenever the window's show type changes. The window's non client | |
75 // view is responsible for updating whether it uses the solo header as part of | |
76 // the repaint by querying GetWindowWithSoloHeader(). | |
77 class SoloWindowTracker::SoloWindowObserver | |
78 : public ash::wm::WindowStateObserver { | |
79 public: | |
80 explicit SoloWindowObserver(aura::Window* window) : window_(window) { | |
81 wm::GetWindowState(window_)->AddObserver(this); | |
82 } | |
83 | |
84 virtual ~SoloWindowObserver() { | |
85 wm::GetWindowState(window_)->RemoveObserver(this); | |
86 } | |
87 | |
88 private: | |
89 // ash::wm::WindowStateObserver override. | |
90 virtual void OnWindowShowTypeChanged( | |
91 ash::wm::WindowState* window_state, | |
92 ash::wm::WindowShowType old_type) OVERRIDE { | |
93 SchedulePaint(window_); | |
94 } | |
95 | |
96 aura::Window* window_; | |
97 | |
98 DISALLOW_COPY_AND_ASSIGN(SoloWindowObserver); | |
99 }; | |
100 | |
101 SoloWindowTracker::SoloWindowTracker(aura::RootWindow* root_window) | |
102 : containers_(GetContainers(root_window)), | |
103 solo_window_(NULL) { | |
104 for (size_t i = 0; i < containers_.size(); ++i) | |
105 containers_[i]->AddObserver(this); | |
106 } | |
107 | |
108 SoloWindowTracker::~SoloWindowTracker() { | |
109 for (size_t i = 0; i < containers_.size(); ++i) | |
110 containers_[i]->RemoveObserver(this); | |
111 } | |
112 | |
113 // static | |
114 void SoloWindowTracker::SetSoloHeaderEnabled(bool enabled) { | |
115 g_solo_header_enabled = enabled; | |
116 std::vector<aura::Window*> root_windows = | |
117 Shell::GetInstance()->GetAllRootWindows(); | |
118 for (size_t i = 0; i < root_windows.size(); ++i) { | |
119 SoloWindowTracker* tracker = | |
120 internal::GetRootWindowController(root_windows[i])-> | |
121 solo_window_tracker(); | |
122 if (tracker) | |
123 tracker->UpdateSoloWindow(NULL); | |
124 } | |
125 } | |
126 | |
127 aura::Window* SoloWindowTracker::GetWindowWithSoloHeader() { | |
128 bool use_solo_header = solo_window_ && | |
129 !wm::GetWindowState(solo_window_)->IsMaximizedOrFullscreen(); | |
130 return use_solo_header ? solo_window_ : NULL; | |
131 } | |
132 | |
133 void SoloWindowTracker::UpdateSoloWindow(aura::Window* ignore_window) { | |
134 std::vector<aura::Window*> candidates; | |
135 // Avoid memory allocations for typical window counts. | |
136 candidates.reserve(16); | |
137 for (size_t i = 0; i < containers_.size(); ++i) { | |
138 candidates.insert(candidates.end(), | |
139 containers_[i]->children().begin(), | |
140 containers_[i]->children().end()); | |
141 } | |
142 | |
143 aura::Window* old_solo_window = solo_window_; | |
144 solo_window_ = NULL; | |
145 if (g_solo_header_enabled && !AnyVisibleWindowDocked()) { | |
146 for (size_t i = 0; i < candidates.size(); ++i) { | |
147 aura::Window* candidate = candidates[i]; | |
148 // Various sorts of windows "don't count" for this computation. | |
149 if (candidate == ignore_window || | |
150 !IsValidCandidate(candidate) || | |
151 !GetTargetVisibility(candidate)) { | |
152 continue; | |
153 } | |
154 | |
155 if (solo_window_) { | |
156 // A window can only use the solo header if it is the only visible valid | |
157 // candidate (and there are no visible docked windows). | |
158 solo_window_ = NULL; | |
159 break; | |
160 } else { | |
161 solo_window_ = candidate; | |
162 } | |
163 } | |
164 } | |
165 | |
166 if (solo_window_ == old_solo_window) | |
167 return; | |
168 | |
169 solo_window_observer_.reset(solo_window_ ? | |
170 new SoloWindowObserver(solo_window_) : NULL); | |
171 if (old_solo_window) | |
172 SchedulePaint(old_solo_window); | |
173 if (solo_window_) | |
174 SchedulePaint(solo_window_); | |
175 } | |
176 | |
177 bool SoloWindowTracker::AnyVisibleWindowDocked() const { | |
178 // For the purpose of SoloWindowTracker, there is a visible docked window if | |
179 // it causes the dock to have non-empty bounds. This is intentionally | |
180 // different from: | |
181 // DockedWindowLayoutManager::IsAnyWindowDocked() and | |
182 // DockedWindowLayoutManager::is_dragged_window_docked(). | |
183 return !dock_bounds_.IsEmpty(); | |
184 } | |
185 | |
186 void SoloWindowTracker::OnWindowAdded(aura::Window* new_window) { | |
187 UpdateSoloWindow(NULL); | |
188 } | |
189 | |
190 void SoloWindowTracker::OnWillRemoveWindow(aura::Window* window) { | |
191 UpdateSoloWindow(window); | |
192 } | |
193 | |
194 void SoloWindowTracker::OnWindowVisibilityChanged(aura::Window* window, | |
195 bool visible) { | |
196 // |window| may be a grandchild of |containers_|. | |
197 std::vector<aura::Window*>::const_iterator it = std::find( | |
198 containers_.begin(), containers_.end(), window->parent()); | |
199 if (it != containers_.end()) | |
200 UpdateSoloWindow(NULL); | |
201 } | |
202 | |
203 void SoloWindowTracker::OnDockBoundsChanging(const gfx::Rect& new_bounds, | |
204 Reason reason) { | |
205 dock_bounds_ = new_bounds; | |
206 UpdateSoloWindow(NULL); | |
207 } | |
208 | |
209 } // namespace ash | |
OLD | NEW |