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/window_state.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/screen_ash.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/wm/window_properties.h"
12 #include "ash/wm/window_state_delegate.h"
13 #include "ash/wm/window_state_observer.h"
14 #include "ash/wm/window_util.h"
15 #include "ash/wm/wm_types.h"
16 #include "base/auto_reset.h"
17 #include "base/command_line.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/window.h"
20 #include "ui/aura/window_delegate.h"
21 #include "ui/gfx/display.h"
22 #include "ui/views/corewm/window_util.h"
23
24 namespace ash {
25 namespace wm {
26
27 // static
IsMaximizedOrFullscreenState(ui::WindowShowState show_state)28 bool WindowState::IsMaximizedOrFullscreenState(ui::WindowShowState show_state) {
29 return show_state == ui::SHOW_STATE_FULLSCREEN ||
30 show_state == ui::SHOW_STATE_MAXIMIZED;
31 }
32
WindowState(aura::Window * window)33 WindowState::WindowState(aura::Window* window)
34 : window_(window),
35 window_position_managed_(false),
36 bounds_changed_by_user_(false),
37 panel_attached_(true),
38 continue_drag_after_reparent_(false),
39 ignored_by_shelf_(false),
40 can_consume_system_keys_(false),
41 top_row_keys_are_function_keys_(false),
42 window_resizer_(NULL),
43 always_restores_to_restore_bounds_(false),
44 hide_shelf_when_fullscreen_(true),
45 animate_to_fullscreen_(true),
46 minimum_visibility_(false),
47 in_set_window_show_type_(false),
48 window_show_type_(ToWindowShowType(GetShowState())) {
49 window_->AddObserver(this);
50
51 #if defined(OS_CHROMEOS)
52 // NOTE(pkotwicz): Animating to immersive fullscreen does not look good. When
53 // the kAshEnableImmersiveFullscreenForAllWindows flag is set most windows
54 // can be put into immersive fullscreen. It is not worth the added complexity
55 // to only animate to fullscreen if the window is put into immersive
56 // fullscreen.
57 animate_to_fullscreen_ = !CommandLine::ForCurrentProcess()->HasSwitch(
58 switches::kAshEnableImmersiveFullscreenForAllWindows);
59 #endif
60 }
61
~WindowState()62 WindowState::~WindowState() {
63 }
64
HasDelegate() const65 bool WindowState::HasDelegate() const {
66 return delegate_;
67 }
68
SetDelegate(scoped_ptr<WindowStateDelegate> delegate)69 void WindowState::SetDelegate(scoped_ptr<WindowStateDelegate> delegate) {
70 DCHECK(!delegate_.get());
71 delegate_ = delegate.Pass();
72 }
73
GetShowState() const74 ui::WindowShowState WindowState::GetShowState() const {
75 return window_->GetProperty(aura::client::kShowStateKey);
76 }
77
IsMinimized() const78 bool WindowState::IsMinimized() const {
79 return GetShowState() == ui::SHOW_STATE_MINIMIZED;
80 }
81
IsMaximized() const82 bool WindowState::IsMaximized() const {
83 return GetShowState() == ui::SHOW_STATE_MAXIMIZED;
84 }
85
IsFullscreen() const86 bool WindowState::IsFullscreen() const {
87 return GetShowState() == ui::SHOW_STATE_FULLSCREEN;
88 }
89
IsMaximizedOrFullscreen() const90 bool WindowState::IsMaximizedOrFullscreen() const {
91 return IsMaximizedOrFullscreenState(GetShowState());
92 }
93
IsNormalShowState() const94 bool WindowState::IsNormalShowState() const {
95 ui::WindowShowState state = window_->GetProperty(aura::client::kShowStateKey);
96 return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT;
97 }
98
IsActive() const99 bool WindowState::IsActive() const {
100 return IsActiveWindow(window_);
101 }
102
IsDocked() const103 bool WindowState::IsDocked() const {
104 return window_->parent() &&
105 window_->parent()->id() == internal::kShellWindowId_DockedContainer;
106 }
107
IsSnapped() const108 bool WindowState::IsSnapped() const {
109 return window_show_type_ == SHOW_TYPE_LEFT_SNAPPED ||
110 window_show_type_ == SHOW_TYPE_RIGHT_SNAPPED;
111 }
112
CanMaximize() const113 bool WindowState::CanMaximize() const {
114 return window_->GetProperty(aura::client::kCanMaximizeKey);
115 }
116
CanMinimize() const117 bool WindowState::CanMinimize() const {
118 internal::RootWindowController* controller =
119 internal::RootWindowController::ForWindow(window_);
120 if (!controller)
121 return false;
122 aura::Window* lockscreen = controller->GetContainer(
123 internal::kShellWindowId_LockScreenContainersContainer);
124 if (lockscreen->Contains(window_))
125 return false;
126
127 return true;
128 }
129
CanResize() const130 bool WindowState::CanResize() const {
131 return window_->GetProperty(aura::client::kCanResizeKey);
132 }
133
CanActivate() const134 bool WindowState::CanActivate() const {
135 return views::corewm::CanActivateWindow(window_);
136 }
137
CanSnap() const138 bool WindowState::CanSnap() const {
139 if (!CanResize() ||
140 window_->type() == aura::client::WINDOW_TYPE_PANEL ||
141 window_->transient_parent())
142 return false;
143 // If a window has a maximum size defined, snapping may make it too big.
144 return window_->delegate() ? window_->delegate()->GetMaximumSize().IsEmpty() :
145 true;
146 }
147
HasRestoreBounds() const148 bool WindowState::HasRestoreBounds() const {
149 return window_->GetProperty(aura::client::kRestoreBoundsKey) != NULL;
150 }
151
Maximize()152 void WindowState::Maximize() {
153 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
154 }
155
SnapLeft(const gfx::Rect & bounds)156 void WindowState::SnapLeft(const gfx::Rect& bounds) {
157 SnapWindow(SHOW_TYPE_LEFT_SNAPPED, bounds);
158 }
159
SnapRight(const gfx::Rect & bounds)160 void WindowState::SnapRight(const gfx::Rect& bounds) {
161 SnapWindow(SHOW_TYPE_RIGHT_SNAPPED, bounds);
162 }
163
Minimize()164 void WindowState::Minimize() {
165 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
166 }
167
Unminimize()168 void WindowState::Unminimize() {
169 window_->SetProperty(
170 aura::client::kShowStateKey,
171 window_->GetProperty(aura::client::kRestoreShowStateKey));
172 window_->ClearProperty(aura::client::kRestoreShowStateKey);
173 }
174
Activate()175 void WindowState::Activate() {
176 ActivateWindow(window_);
177 }
178
Deactivate()179 void WindowState::Deactivate() {
180 DeactivateWindow(window_);
181 }
182
Restore()183 void WindowState::Restore() {
184 window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
185 }
186
ToggleMaximized()187 void WindowState::ToggleMaximized() {
188 if (IsMaximized())
189 Restore();
190 else if (CanMaximize())
191 Maximize();
192 }
193
ToggleFullscreen()194 void WindowState::ToggleFullscreen() {
195 // Window which cannot be maximized should not be fullscreened.
196 // It can, however, be restored if it was fullscreened.
197 bool is_fullscreen = IsFullscreen();
198 if (!is_fullscreen && !CanMaximize())
199 return;
200 if (delegate_ && delegate_->ToggleFullscreen(this))
201 return;
202 if (is_fullscreen) {
203 Restore();
204 } else {
205 window_->SetProperty(aura::client::kShowStateKey,
206 ui::SHOW_STATE_FULLSCREEN);
207 }
208 }
209
SetBoundsInScreen(const gfx::Rect & bounds_in_screen)210 void WindowState::SetBoundsInScreen(
211 const gfx::Rect& bounds_in_screen) {
212 gfx::Rect bounds_in_parent =
213 ScreenAsh::ConvertRectFromScreen(window_->parent(),
214 bounds_in_screen);
215 window_->SetBounds(bounds_in_parent);
216 }
217
SaveCurrentBoundsForRestore()218 void WindowState::SaveCurrentBoundsForRestore() {
219 gfx::Rect bounds_in_screen =
220 ScreenAsh::ConvertRectToScreen(window_->parent(),
221 window_->bounds());
222 SetRestoreBoundsInScreen(bounds_in_screen);
223 }
224
GetRestoreBoundsInScreen() const225 gfx::Rect WindowState::GetRestoreBoundsInScreen() const {
226 return *window_->GetProperty(aura::client::kRestoreBoundsKey);
227 }
228
GetRestoreBoundsInParent() const229 gfx::Rect WindowState::GetRestoreBoundsInParent() const {
230 return ScreenAsh::ConvertRectFromScreen(window_->parent(),
231 GetRestoreBoundsInScreen());
232 }
233
SetRestoreBoundsInScreen(const gfx::Rect & bounds)234 void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) {
235 window_->SetProperty(aura::client::kRestoreBoundsKey, new gfx::Rect(bounds));
236 }
237
SetRestoreBoundsInParent(const gfx::Rect & bounds)238 void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) {
239 SetRestoreBoundsInScreen(
240 ScreenAsh::ConvertRectToScreen(window_->parent(), bounds));
241 }
242
ClearRestoreBounds()243 void WindowState::ClearRestoreBounds() {
244 window_->ClearProperty(aura::client::kRestoreBoundsKey);
245 }
246
SetPreAutoManageWindowBounds(const gfx::Rect & bounds)247 void WindowState::SetPreAutoManageWindowBounds(
248 const gfx::Rect& bounds) {
249 pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds));
250 }
251
AddObserver(WindowStateObserver * observer)252 void WindowState::AddObserver(WindowStateObserver* observer) {
253 observer_list_.AddObserver(observer);
254 }
255
RemoveObserver(WindowStateObserver * observer)256 void WindowState::RemoveObserver(WindowStateObserver* observer) {
257 observer_list_.RemoveObserver(observer);
258 }
259
OnWindowPropertyChanged(aura::Window * window,const void * key,intptr_t old)260 void WindowState::OnWindowPropertyChanged(aura::Window* window,
261 const void* key,
262 intptr_t old) {
263 DCHECK_EQ(window, window_);
264 if (key == aura::client::kShowStateKey)
265 SetWindowShowType(ToWindowShowType(GetShowState()));
266 }
267
SnapWindow(WindowShowType left_or_right,const gfx::Rect & bounds)268 void WindowState::SnapWindow(WindowShowType left_or_right,
269 const gfx::Rect& bounds) {
270 if (window_show_type_ == left_or_right) {
271 window_->SetBounds(bounds);
272 return;
273 }
274
275 // Compute the bounds that the window will restore to. If the window does not
276 // already have restore bounds, it will be restored (when un-snapped) to the
277 // last bounds that it had before getting snapped.
278 gfx::Rect restore_bounds_in_screen(HasRestoreBounds() ?
279 GetRestoreBoundsInScreen() : window_->GetBoundsInScreen());
280 // Set the window's restore bounds so that WorkspaceLayoutManager knows
281 // which width to use when the snapped window is moved to the edge.
282 SetRestoreBoundsInParent(bounds);
283
284 bool was_maximized = IsMaximizedOrFullscreen();
285 // Before we can set the bounds we need to restore the window.
286 // Restoring the window will set the window to its restored bounds set above.
287 // Restore will cause OnWindowPropertyChanged() so it needs to be done
288 // before notifying that the WindowShowType has changed to |left_or_right|.
289 if (was_maximized)
290 Restore();
291 DCHECK(left_or_right == SHOW_TYPE_LEFT_SNAPPED ||
292 left_or_right == SHOW_TYPE_RIGHT_SNAPPED);
293 SetWindowShowType(left_or_right);
294 // TODO(varkha): Ideally the bounds should be changed in a LayoutManager upon
295 // observing the WindowShowType change.
296 // If the window is a child of kShellWindowId_DockedContainer such as during
297 // a drag, the window's bounds are not set in
298 // WorkspaceLayoutManager::OnWindowShowTypeChanged(). Set them here. Skip
299 // setting the bounds otherwise to avoid stopping the slide animation which
300 // was started as a result of OnWindowShowTypeChanged().
301 if (IsDocked())
302 window_->SetBounds(bounds);
303 SetRestoreBoundsInScreen(restore_bounds_in_screen);
304 }
305
SetWindowShowType(WindowShowType new_window_show_type)306 void WindowState::SetWindowShowType(WindowShowType new_window_show_type) {
307 if (in_set_window_show_type_)
308 return;
309 base::AutoReset<bool> resetter(&in_set_window_show_type_, true);
310
311 ui::WindowShowState new_window_state =
312 ToWindowShowState(new_window_show_type);
313 if (new_window_state != GetShowState())
314 window_->SetProperty(aura::client::kShowStateKey, new_window_state);
315 WindowShowType old_window_show_type = window_show_type_;
316 window_show_type_ = new_window_show_type;
317 if (old_window_show_type != window_show_type_) {
318 FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
319 OnWindowShowTypeChanged(this, old_window_show_type));
320 }
321 }
322
GetActiveWindowState()323 WindowState* GetActiveWindowState() {
324 aura::Window* active = GetActiveWindow();
325 return active ? GetWindowState(active) : NULL;
326 }
327
GetWindowState(aura::Window * window)328 WindowState* GetWindowState(aura::Window* window) {
329 if (!window)
330 return NULL;
331 WindowState* settings = window->GetProperty(internal::kWindowStateKey);
332 if(!settings) {
333 settings = new WindowState(window);
334 window->SetProperty(internal::kWindowStateKey, settings);
335 }
336 return settings;
337 }
338
GetWindowState(const aura::Window * window)339 const WindowState* GetWindowState(const aura::Window* window) {
340 return GetWindowState(const_cast<aura::Window*>(window));
341 }
342
343 } // namespace wm
344 } // namespace ash
345