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