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/common/window_state.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "ash/wm/common/default_state.h" | |
10 #include "ash/wm/common/window_positioning_utils.h" | |
11 #include "ash/wm/common/window_state_delegate.h" | |
12 #include "ash/wm/common/window_state_observer.h" | |
13 #include "ash/wm/common/wm_event.h" | |
14 #include "ash/wm/common/wm_screen_util.h" | |
15 #include "ash/wm/common/wm_window.h" | |
16 #include "base/auto_reset.h" | |
17 | |
18 namespace ash { | |
19 namespace wm { | |
20 | |
21 namespace { | |
22 | |
23 WMEventType WMEventTypeFromShowState(ui::WindowShowState requested_show_state) { | |
24 switch (requested_show_state) { | |
25 case ui::SHOW_STATE_DEFAULT: | |
26 case ui::SHOW_STATE_NORMAL: | |
27 return WM_EVENT_NORMAL; | |
28 case ui::SHOW_STATE_MINIMIZED: | |
29 return WM_EVENT_MINIMIZE; | |
30 case ui::SHOW_STATE_MAXIMIZED: | |
31 return WM_EVENT_MAXIMIZE; | |
32 case ui::SHOW_STATE_FULLSCREEN: | |
33 return WM_EVENT_FULLSCREEN; | |
34 case ui::SHOW_STATE_INACTIVE: | |
35 return WM_EVENT_SHOW_INACTIVE; | |
36 case ui::SHOW_STATE_DOCKED: | |
37 return WM_EVENT_DOCK; | |
38 case ui::SHOW_STATE_END: | |
39 NOTREACHED() << "No WMEvent defined for the show state:" | |
40 << requested_show_state; | |
41 } | |
42 return WM_EVENT_NORMAL; | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 WindowState::~WindowState() {} | |
48 | |
49 bool WindowState::HasDelegate() const { | |
50 return !!delegate_; | |
51 } | |
52 | |
53 void WindowState::SetDelegate(std::unique_ptr<WindowStateDelegate> delegate) { | |
54 DCHECK(!delegate_.get()); | |
55 delegate_ = std::move(delegate); | |
56 } | |
57 | |
58 WindowStateType WindowState::GetStateType() const { | |
59 return current_state_->GetType(); | |
60 } | |
61 | |
62 bool WindowState::IsMinimized() const { | |
63 return GetStateType() == WINDOW_STATE_TYPE_MINIMIZED || | |
64 GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; | |
65 } | |
66 | |
67 bool WindowState::IsMaximized() const { | |
68 return GetStateType() == WINDOW_STATE_TYPE_MAXIMIZED; | |
69 } | |
70 | |
71 bool WindowState::IsFullscreen() const { | |
72 return GetStateType() == WINDOW_STATE_TYPE_FULLSCREEN; | |
73 } | |
74 | |
75 bool WindowState::IsMaximizedOrFullscreen() const { | |
76 return GetStateType() == WINDOW_STATE_TYPE_FULLSCREEN || | |
77 GetStateType() == WINDOW_STATE_TYPE_MAXIMIZED; | |
78 } | |
79 | |
80 bool WindowState::IsSnapped() const { | |
81 return GetStateType() == WINDOW_STATE_TYPE_LEFT_SNAPPED || | |
82 GetStateType() == WINDOW_STATE_TYPE_RIGHT_SNAPPED; | |
83 } | |
84 | |
85 bool WindowState::IsNormalStateType() const { | |
86 return GetStateType() == WINDOW_STATE_TYPE_NORMAL || | |
87 GetStateType() == WINDOW_STATE_TYPE_DEFAULT; | |
88 } | |
89 | |
90 bool WindowState::IsNormalOrSnapped() const { | |
91 return IsNormalStateType() || IsSnapped(); | |
92 } | |
93 | |
94 bool WindowState::IsActive() const { | |
95 return window_->IsActive(); | |
96 } | |
97 | |
98 bool WindowState::IsDocked() const { | |
99 return GetStateType() == WINDOW_STATE_TYPE_DOCKED || | |
100 GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; | |
101 } | |
102 | |
103 bool WindowState::IsUserPositionable() const { | |
104 return (window_->GetType() == ui::wm::WINDOW_TYPE_NORMAL || | |
105 window_->GetType() == ui::wm::WINDOW_TYPE_PANEL); | |
106 } | |
107 | |
108 bool WindowState::CanMaximize() const { | |
109 // Window must have the kCanMaximizeKey and have no maximum width or height. | |
110 if (!window_->CanMaximize()) | |
111 return false; | |
112 | |
113 if (!window_->HasNonClientArea()) | |
114 return true; | |
115 | |
116 gfx::Size max_size = window_->GetMaximumSize(); | |
117 return !max_size.width() && !max_size.height(); | |
118 } | |
119 | |
120 bool WindowState::CanMinimize() const { | |
121 return window_->CanMinimize(); | |
122 } | |
123 | |
124 bool WindowState::CanResize() const { | |
125 return window_->CanResize(); | |
126 } | |
127 | |
128 bool WindowState::CanActivate() const { | |
129 return window_->CanActivate(); | |
130 } | |
131 | |
132 bool WindowState::CanSnap() const { | |
133 if (!CanResize() || window_->GetType() == ui::wm::WINDOW_TYPE_PANEL || | |
134 window_->GetTransientParent()) { | |
135 return false; | |
136 } | |
137 // If a window cannot be maximized, assume it cannot snap either. | |
138 // TODO(oshima): We should probably snap if the maximum size is greater than | |
139 // the snapped size. | |
140 return CanMaximize(); | |
141 } | |
142 | |
143 bool WindowState::HasRestoreBounds() const { | |
144 return window_->HasRestoreBounds(); | |
145 } | |
146 | |
147 void WindowState::Maximize() { | |
148 window_->Maximize(); | |
149 } | |
150 | |
151 void WindowState::Minimize() { | |
152 window_->Minimize(); | |
153 } | |
154 | |
155 void WindowState::Unminimize() { | |
156 window_->Unminimize(); | |
157 } | |
158 | |
159 void WindowState::Activate() { | |
160 window_->Activate(); | |
161 } | |
162 | |
163 void WindowState::Deactivate() { | |
164 window_->Deactivate(); | |
165 } | |
166 | |
167 void WindowState::Restore() { | |
168 if (!IsNormalStateType()) { | |
169 const WMEvent event(WM_EVENT_NORMAL); | |
170 OnWMEvent(&event); | |
171 } | |
172 } | |
173 | |
174 void WindowState::DisableAlwaysOnTop(WmWindow* window_on_top) { | |
175 DCHECK(window_on_top); | |
176 if (GetAlwaysOnTop()) { | |
177 // |window_| is hidden first to avoid canceling fullscreen mode when it is | |
178 // no longer always on top and gets added to default container. This avoids | |
179 // sending redundant OnFullscreenStateChanged to the layout manager. The | |
180 // |window_| visibility is restored after it no longer obscures the | |
181 // |window_on_top|. | |
182 bool visible = window_->IsVisible(); | |
183 if (visible) | |
184 window_->Hide(); | |
185 window_->SetAlwaysOnTop(false); | |
186 // Technically it is possible that a |window_| could make itself | |
187 // always_on_top really quickly. This is probably not a realistic case but | |
188 // check if the two windows are in the same container just in case. | |
189 if (window_on_top->GetParent() == window_->GetParent()) | |
190 window_->GetParent()->StackChildAbove(window_on_top, window_); | |
191 if (visible) | |
192 window_->Show(); | |
193 cached_always_on_top_ = true; | |
194 } | |
195 } | |
196 | |
197 void WindowState::RestoreAlwaysOnTop() { | |
198 if (delegate() && delegate()->RestoreAlwaysOnTop(this)) | |
199 return; | |
200 if (cached_always_on_top_) { | |
201 cached_always_on_top_ = false; | |
202 window_->SetAlwaysOnTop(true); | |
203 } | |
204 } | |
205 | |
206 void WindowState::OnWMEvent(const WMEvent* event) { | |
207 current_state_->OnWMEvent(this, event); | |
208 } | |
209 | |
210 void WindowState::SaveCurrentBoundsForRestore() { | |
211 gfx::Rect bounds_in_screen = | |
212 window_->GetParent()->ConvertRectToScreen(window_->GetBounds()); | |
213 SetRestoreBoundsInScreen(bounds_in_screen); | |
214 } | |
215 | |
216 gfx::Rect WindowState::GetRestoreBoundsInScreen() const { | |
217 return window_->GetRestoreBoundsInScreen(); | |
218 } | |
219 | |
220 gfx::Rect WindowState::GetRestoreBoundsInParent() const { | |
221 return window_->GetParent()->ConvertRectFromScreen( | |
222 GetRestoreBoundsInScreen()); | |
223 } | |
224 | |
225 void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) { | |
226 window_->SetRestoreBoundsInScreen(bounds); | |
227 } | |
228 | |
229 void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) { | |
230 SetRestoreBoundsInScreen(window_->GetParent()->ConvertRectToScreen(bounds)); | |
231 } | |
232 | |
233 void WindowState::ClearRestoreBounds() { | |
234 window_->ClearRestoreBounds(); | |
235 } | |
236 | |
237 std::unique_ptr<WindowState::State> WindowState::SetStateObject( | |
238 std::unique_ptr<WindowState::State> new_state) { | |
239 current_state_->DetachState(this); | |
240 std::unique_ptr<WindowState::State> old_object = std::move(current_state_); | |
241 current_state_ = std::move(new_state); | |
242 current_state_->AttachState(this, old_object.get()); | |
243 return old_object; | |
244 } | |
245 | |
246 void WindowState::SetPreAutoManageWindowBounds(const gfx::Rect& bounds) { | |
247 pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds)); | |
248 } | |
249 | |
250 void WindowState::AddObserver(WindowStateObserver* observer) { | |
251 observer_list_.AddObserver(observer); | |
252 } | |
253 | |
254 void WindowState::RemoveObserver(WindowStateObserver* observer) { | |
255 observer_list_.RemoveObserver(observer); | |
256 } | |
257 | |
258 void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) { | |
259 bounds_changed_by_user_ = bounds_changed_by_user; | |
260 if (bounds_changed_by_user) | |
261 pre_auto_manage_window_bounds_.reset(); | |
262 } | |
263 | |
264 void WindowState::CreateDragDetails(const gfx::Point& point_in_parent, | |
265 int window_component, | |
266 aura::client::WindowMoveSource source) { | |
267 drag_details_.reset( | |
268 new DragDetails(window_, point_in_parent, window_component, source)); | |
269 } | |
270 | |
271 void WindowState::DeleteDragDetails() { | |
272 drag_details_.reset(); | |
273 } | |
274 | |
275 void WindowState::SetAndClearRestoreBounds() { | |
276 DCHECK(HasRestoreBounds()); | |
277 SetBoundsInScreen(GetRestoreBoundsInScreen()); | |
278 ClearRestoreBounds(); | |
279 } | |
280 | |
281 void WindowState::OnWindowShowStateChanged() { | |
282 if (!ignore_property_change_) { | |
283 WMEvent event(WMEventTypeFromShowState(GetShowState())); | |
284 OnWMEvent(&event); | |
285 } | |
286 } | |
287 | |
288 WindowState::WindowState(WmWindow* window) | |
289 : window_(window), | |
290 window_position_managed_(false), | |
291 bounds_changed_by_user_(false), | |
292 panel_attached_(true), | |
293 ignored_by_shelf_(false), | |
294 can_consume_system_keys_(false), | |
295 top_row_keys_are_function_keys_(false), | |
296 unminimize_to_restore_bounds_(false), | |
297 in_immersive_fullscreen_(false), | |
298 hide_shelf_when_fullscreen_(true), | |
299 minimum_visibility_(false), | |
300 can_be_dragged_(true), | |
301 cached_always_on_top_(false), | |
302 ignore_property_change_(false), | |
303 current_state_(new DefaultState(ToWindowStateType(GetShowState()))) {} | |
304 | |
305 bool WindowState::GetAlwaysOnTop() const { | |
306 return window_->IsAlwaysOnTop(); | |
307 } | |
308 | |
309 ui::WindowShowState WindowState::GetShowState() const { | |
310 return window_->GetShowState(); | |
311 } | |
312 | |
313 void WindowState::SetBoundsInScreen(const gfx::Rect& bounds_in_screen) { | |
314 gfx::Rect bounds_in_parent = | |
315 window_->GetParent()->ConvertRectFromScreen(bounds_in_screen); | |
316 window_->SetBounds(bounds_in_parent); | |
317 } | |
318 | |
319 void WindowState::AdjustSnappedBounds(gfx::Rect* bounds) { | |
320 if (is_dragged() || !IsSnapped()) | |
321 return; | |
322 gfx::Rect maximized_bounds = GetMaximizedWindowBoundsInParent(window_); | |
323 if (GetStateType() == WINDOW_STATE_TYPE_LEFT_SNAPPED) | |
324 bounds->set_x(maximized_bounds.x()); | |
325 else if (GetStateType() == WINDOW_STATE_TYPE_RIGHT_SNAPPED) | |
326 bounds->set_x(maximized_bounds.right() - bounds->width()); | |
327 bounds->set_y(maximized_bounds.y()); | |
328 bounds->set_height(maximized_bounds.height()); | |
329 } | |
330 | |
331 void WindowState::UpdateWindowShowStateFromStateType() { | |
332 ui::WindowShowState new_window_state = | |
333 ToWindowShowState(current_state_->GetType()); | |
334 if (new_window_state != GetShowState()) { | |
335 base::AutoReset<bool> resetter(&ignore_property_change_, true); | |
336 window_->SetShowState(new_window_state); | |
337 } | |
338 } | |
339 | |
340 void WindowState::NotifyPreStateTypeChange( | |
341 WindowStateType old_window_state_type) { | |
342 FOR_EACH_OBSERVER(WindowStateObserver, observer_list_, | |
343 OnPreWindowStateTypeChange(this, old_window_state_type)); | |
344 } | |
345 | |
346 void WindowState::NotifyPostStateTypeChange( | |
347 WindowStateType old_window_state_type) { | |
348 FOR_EACH_OBSERVER(WindowStateObserver, observer_list_, | |
349 OnPostWindowStateTypeChange(this, old_window_state_type)); | |
350 } | |
351 | |
352 void WindowState::SetBoundsDirect(const gfx::Rect& bounds) { | |
353 gfx::Rect actual_new_bounds(bounds); | |
354 // Ensure we don't go smaller than our minimum bounds in "normal" window | |
355 // modes | |
356 if (window_->HasNonClientArea() && !IsMaximized() && !IsFullscreen()) { | |
357 // Get the minimum usable size of the minimum size and the screen size. | |
358 gfx::Size min_size = window_->GetMinimumSize(); | |
359 min_size.SetToMin(window_->GetDisplayNearestWindow().work_area().size()); | |
360 | |
361 actual_new_bounds.set_width( | |
362 std::max(min_size.width(), actual_new_bounds.width())); | |
363 actual_new_bounds.set_height( | |
364 std::max(min_size.height(), actual_new_bounds.height())); | |
365 } | |
366 window_->SetBoundsDirect(actual_new_bounds); | |
367 } | |
368 | |
369 void WindowState::SetBoundsConstrained(const gfx::Rect& bounds) { | |
370 gfx::Rect work_area_in_parent = GetDisplayWorkAreaBoundsInParent(window_); | |
371 gfx::Rect child_bounds(bounds); | |
372 AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds); | |
373 SetBoundsDirect(child_bounds); | |
374 } | |
375 | |
376 void WindowState::SetBoundsDirectAnimated(const gfx::Rect& bounds) { | |
377 window_->SetBoundsDirectAnimated(bounds); | |
378 } | |
379 | |
380 void WindowState::SetBoundsDirectCrossFade(const gfx::Rect& new_bounds) { | |
381 // Some test results in invoking CrossFadeToBounds when window is not visible. | |
382 // No animation is necessary in that case, thus just change the bounds and | |
383 // quit. | |
384 if (!window_->GetTargetVisibility()) { | |
385 SetBoundsConstrained(new_bounds); | |
386 return; | |
387 } | |
388 | |
389 window_->SetBoundsDirectCrossFade(new_bounds); | |
390 } | |
391 | |
392 } // namespace wm | |
393 } // namespace ash | |
OLD | NEW |