Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: ash/wm/common/default_state.cc

Issue 2030593002: Renames ash/wm/common into ash/common/wm (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ash/wm/common/default_state.h ('k') | ash/wm/common/default_window_resizer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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/default_state.h"
6
7 #include "ash/wm/common/dock/docked_window_layout_manager.h"
8 #include "ash/wm/common/window_animation_types.h"
9 #include "ash/wm/common/window_parenting_utils.h"
10 #include "ash/wm/common/window_positioning_utils.h"
11 #include "ash/wm/common/window_state.h"
12 #include "ash/wm/common/window_state_delegate.h"
13 #include "ash/wm/common/window_state_util.h"
14 #include "ash/wm/common/wm_event.h"
15 #include "ash/wm/common/wm_globals.h"
16 #include "ash/wm/common/wm_root_window_controller.h"
17 #include "ash/wm/common/wm_screen_util.h"
18 #include "ash/wm/common/wm_shell_window_ids.h"
19 #include "ash/wm/common/wm_window.h"
20 #include "ui/display/display.h"
21 #include "ui/display/screen.h"
22
23 namespace ash {
24 namespace wm {
25 namespace {
26
27 // This specifies how much percent (30%) of a window rect
28 // must be visible when the window is added to the workspace.
29 const float kMinimumPercentOnScreenArea = 0.3f;
30
31 // When a window that has restore bounds at least as large as a work area is
32 // unmaximized, inset the bounds slightly so that they are not exactly the same.
33 // This makes it easier to resize the window.
34 const int kMaximizedWindowInset = 10; // DIPs.
35
36 bool IsMinimizedWindowState(const WindowStateType state_type) {
37 return state_type == WINDOW_STATE_TYPE_MINIMIZED ||
38 state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED;
39 }
40
41 void MoveToDisplayForRestore(WindowState* window_state) {
42 if (!window_state->HasRestoreBounds())
43 return;
44 const gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen();
45
46 // Move only if the restore bounds is outside of
47 // the display. There is no information about in which
48 // display it should be restored, so this is best guess.
49 // TODO(oshima): Restore information should contain the
50 // work area information like WindowResizer does for the
51 // last window location.
52 gfx::Rect display_area =
53 window_state->window()->GetDisplayNearestWindow().bounds();
54
55 if (!display_area.Intersects(restore_bounds)) {
56 const display::Display& display =
57 display::Screen::GetScreen()->GetDisplayMatching(restore_bounds);
58 WmGlobals* globals = window_state->window()->GetGlobals();
59 WmWindow* new_root = globals->GetRootWindowForDisplayId(display.id());
60 if (new_root != window_state->window()->GetRootWindow()) {
61 WmWindow* new_container = new_root->GetChildByShellWindowId(
62 window_state->window()->GetParent()->GetShellWindowId());
63 new_container->AddChild(window_state->window());
64 }
65 }
66 }
67
68 DockedWindowLayoutManager* GetDockedWindowLayoutManager(WmGlobals* globals) {
69 return DockedWindowLayoutManager::Get(globals->GetActiveWindow());
70 }
71
72 class ScopedPreferredAlignmentResetter {
73 public:
74 ScopedPreferredAlignmentResetter(DockedAlignment dock_alignment,
75 DockedWindowLayoutManager* dock_layout)
76 : docked_window_layout_manager_(dock_layout) {
77 docked_window_layout_manager_->set_preferred_alignment(dock_alignment);
78 }
79 ~ScopedPreferredAlignmentResetter() {
80 docked_window_layout_manager_->set_preferred_alignment(
81 DOCKED_ALIGNMENT_NONE);
82 }
83
84 private:
85 DockedWindowLayoutManager* docked_window_layout_manager_;
86
87 DISALLOW_COPY_AND_ASSIGN(ScopedPreferredAlignmentResetter);
88 };
89
90 class ScopedDockedLayoutEventSourceResetter {
91 public:
92 ScopedDockedLayoutEventSourceResetter(DockedWindowLayoutManager* dock_layout)
93 : docked_window_layout_manager_(dock_layout) {
94 docked_window_layout_manager_->set_event_source(
95 DOCKED_ACTION_SOURCE_KEYBOARD);
96 }
97 ~ScopedDockedLayoutEventSourceResetter() {
98 docked_window_layout_manager_->set_event_source(
99 DOCKED_ACTION_SOURCE_UNKNOWN);
100 }
101
102 private:
103 DockedWindowLayoutManager* docked_window_layout_manager_;
104
105 DISALLOW_COPY_AND_ASSIGN(ScopedDockedLayoutEventSourceResetter);
106 };
107
108 void CycleSnapDock(WindowState* window_state, WMEventType event) {
109 DockedWindowLayoutManager* dock_layout =
110 GetDockedWindowLayoutManager(window_state->window()->GetGlobals());
111 wm::WindowStateType desired_snap_state =
112 event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT
113 ? wm::WINDOW_STATE_TYPE_LEFT_SNAPPED
114 : wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED;
115 DockedAlignment desired_dock_alignment =
116 event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT ? DOCKED_ALIGNMENT_LEFT
117 : DOCKED_ALIGNMENT_RIGHT;
118 DockedAlignment current_dock_alignment =
119 dock_layout ? dock_layout->CalculateAlignment() : DOCKED_ALIGNMENT_NONE;
120
121 if (!window_state->IsDocked() ||
122 (current_dock_alignment != DOCKED_ALIGNMENT_NONE &&
123 current_dock_alignment != desired_dock_alignment)) {
124 if (window_state->CanSnap() &&
125 window_state->GetStateType() != desired_snap_state &&
126 window_state->window()->GetType() != ui::wm::WINDOW_TYPE_PANEL) {
127 const wm::WMEvent event(desired_snap_state ==
128 wm::WINDOW_STATE_TYPE_LEFT_SNAPPED
129 ? wm::WM_EVENT_SNAP_LEFT
130 : wm::WM_EVENT_SNAP_RIGHT);
131 window_state->OnWMEvent(&event);
132 return;
133 }
134
135 if (dock_layout &&
136 dock_layout->CanDockWindow(window_state->window(),
137 desired_dock_alignment)) {
138 if (window_state->IsDocked()) {
139 dock_layout->MaybeSetDesiredDockedAlignment(desired_dock_alignment);
140 return;
141 }
142
143 ScopedDockedLayoutEventSourceResetter event_source_resetter(dock_layout);
144 ScopedPreferredAlignmentResetter alignmentResetter(desired_dock_alignment,
145 dock_layout);
146 const wm::WMEvent event(wm::WM_EVENT_DOCK);
147 window_state->OnWMEvent(&event);
148 return;
149 }
150 }
151
152 if (window_state->IsDocked() || window_state->IsSnapped()) {
153 ScopedDockedLayoutEventSourceResetter event_source_resetter(dock_layout);
154 window_state->Restore();
155 return;
156 }
157 window_state->window()->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE);
158 }
159
160 } // namespace
161
162 DefaultState::DefaultState(WindowStateType initial_state_type)
163 : state_type_(initial_state_type), stored_window_state_(nullptr) {}
164 DefaultState::~DefaultState() {}
165
166 void DefaultState::OnWMEvent(WindowState* window_state, const WMEvent* event) {
167 if (ProcessWorkspaceEvents(window_state, event))
168 return;
169
170 if (ProcessCompoundEvents(window_state, event))
171 return;
172
173 WindowStateType current_state_type = window_state->GetStateType();
174 WindowStateType next_state_type = WINDOW_STATE_TYPE_NORMAL;
175 switch (event->type()) {
176 case WM_EVENT_NORMAL:
177 next_state_type = current_state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED
178 ? WINDOW_STATE_TYPE_DOCKED
179 : WINDOW_STATE_TYPE_NORMAL;
180 break;
181 case WM_EVENT_MAXIMIZE:
182 next_state_type = WINDOW_STATE_TYPE_MAXIMIZED;
183 break;
184 case WM_EVENT_MINIMIZE:
185 next_state_type = current_state_type == WINDOW_STATE_TYPE_DOCKED
186 ? WINDOW_STATE_TYPE_DOCKED_MINIMIZED
187 : WINDOW_STATE_TYPE_MINIMIZED;
188 break;
189 case WM_EVENT_FULLSCREEN:
190 next_state_type = WINDOW_STATE_TYPE_FULLSCREEN;
191 break;
192 case WM_EVENT_SNAP_LEFT:
193 next_state_type = WINDOW_STATE_TYPE_LEFT_SNAPPED;
194 break;
195 case WM_EVENT_SNAP_RIGHT:
196 next_state_type = WINDOW_STATE_TYPE_RIGHT_SNAPPED;
197 break;
198 case WM_EVENT_DOCK:
199 next_state_type = WINDOW_STATE_TYPE_DOCKED;
200 break;
201 case WM_EVENT_SET_BOUNDS:
202 SetBounds(window_state, static_cast<const SetBoundsEvent*>(event));
203 return;
204 case WM_EVENT_SHOW_INACTIVE:
205 next_state_type = WINDOW_STATE_TYPE_INACTIVE;
206 break;
207 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
208 case WM_EVENT_TOGGLE_MAXIMIZE:
209 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
210 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
211 case WM_EVENT_TOGGLE_FULLSCREEN:
212 case WM_EVENT_CYCLE_SNAP_DOCK_LEFT:
213 case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT:
214 case WM_EVENT_CENTER:
215 NOTREACHED() << "Compound event should not reach here:" << event;
216 return;
217 case WM_EVENT_ADDED_TO_WORKSPACE:
218 case WM_EVENT_WORKAREA_BOUNDS_CHANGED:
219 case WM_EVENT_DISPLAY_BOUNDS_CHANGED:
220 NOTREACHED() << "Workspace event should not reach here:" << event;
221 return;
222 }
223
224 if (next_state_type == current_state_type && window_state->IsSnapped()) {
225 gfx::Rect snapped_bounds =
226 event->type() == WM_EVENT_SNAP_LEFT
227 ? GetDefaultLeftSnappedWindowBoundsInParent(window_state->window())
228 : GetDefaultRightSnappedWindowBoundsInParent(
229 window_state->window());
230 window_state->SetBoundsDirectAnimated(snapped_bounds);
231 return;
232 }
233
234 EnterToNextState(window_state, next_state_type);
235 }
236
237 WindowStateType DefaultState::GetType() const {
238 return state_type_;
239 }
240
241 void DefaultState::AttachState(WindowState* window_state,
242 WindowState::State* state_in_previous_mode) {
243 DCHECK_EQ(stored_window_state_, window_state);
244
245 ReenterToCurrentState(window_state, state_in_previous_mode);
246
247 // If the display has changed while in the another mode,
248 // we need to let windows know the change.
249 display::Display current_display =
250 window_state->window()->GetDisplayNearestWindow();
251 if (stored_display_state_.bounds() != current_display.bounds()) {
252 const WMEvent event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED);
253 window_state->OnWMEvent(&event);
254 } else if (stored_display_state_.work_area() != current_display.work_area()) {
255 const WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED);
256 window_state->OnWMEvent(&event);
257 }
258 }
259
260 void DefaultState::DetachState(WindowState* window_state) {
261 stored_window_state_ = window_state;
262 stored_bounds_ = window_state->window()->GetBounds();
263 stored_restore_bounds_ = window_state->HasRestoreBounds()
264 ? window_state->GetRestoreBoundsInParent()
265 : gfx::Rect();
266 // Remember the display state so that in case of the display change
267 // while in the other mode, we can perform necessary action to
268 // restore the window state to the proper state for the current
269 // display.
270 stored_display_state_ = window_state->window()->GetDisplayNearestWindow();
271 }
272
273 // static
274 bool DefaultState::ProcessCompoundEvents(WindowState* window_state,
275 const WMEvent* event) {
276 WmWindow* window = window_state->window();
277
278 switch (event->type()) {
279 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
280 if (window_state->IsFullscreen()) {
281 const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
282 window_state->OnWMEvent(&event);
283 } else if (window_state->IsMaximized()) {
284 window_state->Restore();
285 } else if (window_state->IsNormalOrSnapped()) {
286 if (window_state->CanMaximize())
287 window_state->Maximize();
288 }
289 return true;
290 case WM_EVENT_TOGGLE_MAXIMIZE:
291 if (window_state->IsFullscreen()) {
292 const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
293 window_state->OnWMEvent(&event);
294 } else if (window_state->IsMaximized()) {
295 window_state->Restore();
296 } else if (window_state->CanMaximize()) {
297 window_state->Maximize();
298 }
299 return true;
300 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: {
301 gfx::Rect work_area = GetDisplayWorkAreaBoundsInParent(window);
302
303 // Maximize vertically if:
304 // - The window does not have a max height defined.
305 // - The window has the normal state type. Snapped windows are excluded
306 // because they are already maximized vertically and reverting to the
307 // restored bounds looks weird.
308 if (window->GetMaximumSize().height() != 0 ||
309 !window_state->IsNormalStateType()) {
310 return true;
311 }
312 if (window_state->HasRestoreBounds() &&
313 (window->GetBounds().height() == work_area.height() &&
314 window->GetBounds().y() == work_area.y())) {
315 window_state->SetAndClearRestoreBounds();
316 } else {
317 window_state->SaveCurrentBoundsForRestore();
318 window->SetBounds(gfx::Rect(window->GetBounds().x(), work_area.y(),
319 window->GetBounds().width(),
320 work_area.height()));
321 }
322 return true;
323 }
324 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: {
325 // Maximize horizontally if:
326 // - The window does not have a max width defined.
327 // - The window is snapped or has the normal state type.
328 if (window->GetMaximumSize().width() != 0)
329 return true;
330 if (!window_state->IsNormalOrSnapped())
331 return true;
332 gfx::Rect work_area = GetDisplayWorkAreaBoundsInParent(window);
333 if (window_state->IsNormalStateType() &&
334 window_state->HasRestoreBounds() &&
335 (window->GetBounds().width() == work_area.width() &&
336 window->GetBounds().x() == work_area.x())) {
337 window_state->SetAndClearRestoreBounds();
338 } else {
339 gfx::Rect new_bounds(work_area.x(), window->GetBounds().y(),
340 work_area.width(), window->GetBounds().height());
341
342 gfx::Rect restore_bounds = window->GetBounds();
343 if (window_state->IsSnapped()) {
344 window_state->SetRestoreBoundsInParent(new_bounds);
345 window_state->Restore();
346
347 // The restore logic prevents a window from being restored to bounds
348 // which match the workspace bounds exactly so it is necessary to set
349 // the bounds again below.
350 }
351
352 window_state->SetRestoreBoundsInParent(restore_bounds);
353 window->SetBounds(new_bounds);
354 }
355 return true;
356 }
357 case WM_EVENT_TOGGLE_FULLSCREEN:
358 ToggleFullScreen(window_state, window_state->delegate());
359 return true;
360 case WM_EVENT_CYCLE_SNAP_DOCK_LEFT:
361 case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT:
362 CycleSnapDock(window_state, event->type());
363 return true;
364 case WM_EVENT_CENTER:
365 CenterWindow(window_state);
366 return true;
367 case WM_EVENT_NORMAL:
368 case WM_EVENT_MAXIMIZE:
369 case WM_EVENT_MINIMIZE:
370 case WM_EVENT_FULLSCREEN:
371 case WM_EVENT_SNAP_LEFT:
372 case WM_EVENT_SNAP_RIGHT:
373 case WM_EVENT_SET_BOUNDS:
374 case WM_EVENT_SHOW_INACTIVE:
375 case WM_EVENT_DOCK:
376 break;
377 case WM_EVENT_ADDED_TO_WORKSPACE:
378 case WM_EVENT_WORKAREA_BOUNDS_CHANGED:
379 case WM_EVENT_DISPLAY_BOUNDS_CHANGED:
380 NOTREACHED() << "Workspace event should not reach here:" << event;
381 break;
382 }
383 return false;
384 }
385
386 bool DefaultState::ProcessWorkspaceEvents(WindowState* window_state,
387 const WMEvent* event) {
388 switch (event->type()) {
389 case WM_EVENT_ADDED_TO_WORKSPACE: {
390 // When a window is dragged and dropped onto a different
391 // root window, the bounds will be updated after they are added
392 // to the root window.
393 // If a window is opened as maximized or fullscreen, its bounds may be
394 // empty, so update the bounds now before checking empty.
395 if (window_state->is_dragged() ||
396 SetMaximizedOrFullscreenBounds(window_state)) {
397 return true;
398 }
399
400 WmWindow* window = window_state->window();
401 gfx::Rect bounds = window->GetBounds();
402
403 // Don't adjust window bounds if the bounds are empty as this
404 // happens when a new views::Widget is created.
405 if (bounds.IsEmpty())
406 return true;
407
408 // Only windows of type WINDOW_TYPE_NORMAL or WINDOW_TYPE_PANEL need to be
409 // adjusted to have minimum visibility, because they are positioned by the
410 // user and user should always be able to interact with them. Other
411 // windows are positioned programmatically.
412 if (!window_state->IsUserPositionable())
413 return true;
414
415 // Use entire display instead of workarea because the workarea can
416 // be further shrunk by the docked area. The logic ensures 30%
417 // visibility which should be enough to see where the window gets
418 // moved.
419 gfx::Rect display_area = GetDisplayBoundsInParent(window);
420 int min_width = bounds.width() * wm::kMinimumPercentOnScreenArea;
421 int min_height = bounds.height() * wm::kMinimumPercentOnScreenArea;
422 wm::AdjustBoundsToEnsureWindowVisibility(display_area, min_width,
423 min_height, &bounds);
424 window_state->AdjustSnappedBounds(&bounds);
425 if (window->GetBounds() != bounds)
426 window_state->SetBoundsConstrained(bounds);
427 return true;
428 }
429 case WM_EVENT_DISPLAY_BOUNDS_CHANGED: {
430 if (window_state->is_dragged() ||
431 SetMaximizedOrFullscreenBounds(window_state)) {
432 return true;
433 }
434 gfx::Rect work_area_in_parent =
435 GetDisplayWorkAreaBoundsInParent(window_state->window());
436 gfx::Rect bounds = window_state->window()->GetBounds();
437 // When display bounds has changed, make sure the entire window is fully
438 // visible.
439 bounds.AdjustToFit(work_area_in_parent);
440 window_state->AdjustSnappedBounds(&bounds);
441 if (window_state->window()->GetBounds() != bounds)
442 window_state->SetBoundsDirectAnimated(bounds);
443 return true;
444 }
445 case WM_EVENT_WORKAREA_BOUNDS_CHANGED: {
446 // Don't resize the maximized window when the desktop is covered
447 // by fullscreen window. crbug.com/504299.
448 bool in_fullscreen =
449 window_state->window()
450 ->GetRootWindowController()
451 ->GetWorkspaceWindowState() == WORKSPACE_WINDOW_STATE_FULL_SCREEN;
452 if (in_fullscreen && window_state->IsMaximized())
453 return true;
454
455 if (window_state->is_dragged() ||
456 SetMaximizedOrFullscreenBounds(window_state)) {
457 return true;
458 }
459 gfx::Rect work_area_in_parent =
460 GetDisplayWorkAreaBoundsInParent(window_state->window());
461 gfx::Rect bounds = window_state->window()->GetBounds();
462 wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent,
463 &bounds);
464 window_state->AdjustSnappedBounds(&bounds);
465 if (window_state->window()->GetBounds() != bounds)
466 window_state->SetBoundsDirectAnimated(bounds);
467 return true;
468 }
469 case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
470 case WM_EVENT_TOGGLE_MAXIMIZE:
471 case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
472 case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
473 case WM_EVENT_TOGGLE_FULLSCREEN:
474 case WM_EVENT_CYCLE_SNAP_DOCK_LEFT:
475 case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT:
476 case WM_EVENT_CENTER:
477 case WM_EVENT_NORMAL:
478 case WM_EVENT_MAXIMIZE:
479 case WM_EVENT_MINIMIZE:
480 case WM_EVENT_FULLSCREEN:
481 case WM_EVENT_SNAP_LEFT:
482 case WM_EVENT_SNAP_RIGHT:
483 case WM_EVENT_SET_BOUNDS:
484 case WM_EVENT_SHOW_INACTIVE:
485 case WM_EVENT_DOCK:
486 break;
487 }
488 return false;
489 }
490
491 // static
492 bool DefaultState::SetMaximizedOrFullscreenBounds(WindowState* window_state) {
493 DCHECK(!window_state->is_dragged());
494 if (window_state->IsMaximized()) {
495 window_state->SetBoundsDirect(
496 GetMaximizedWindowBoundsInParent(window_state->window()));
497 return true;
498 }
499 if (window_state->IsFullscreen()) {
500 window_state->SetBoundsDirect(
501 GetDisplayBoundsInParent(window_state->window()));
502 return true;
503 }
504 return false;
505 }
506
507 // static
508 void DefaultState::SetBounds(WindowState* window_state,
509 const SetBoundsEvent* event) {
510 if (window_state->is_dragged()) {
511 // TODO(oshima|varkha): This may be no longer needed, as the dragging
512 // happens in docked window container. crbug.com/485612.
513 window_state->SetBoundsDirect(event->requested_bounds());
514 } else if (window_state->IsSnapped()) {
515 gfx::Rect work_area_in_parent =
516 GetDisplayWorkAreaBoundsInParent(window_state->window());
517 gfx::Rect child_bounds(event->requested_bounds());
518 wm::AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds);
519 window_state->AdjustSnappedBounds(&child_bounds);
520 window_state->SetBoundsDirect(child_bounds);
521 } else if (!SetMaximizedOrFullscreenBounds(window_state)) {
522 window_state->SetBoundsConstrained(event->requested_bounds());
523 }
524 }
525
526 void DefaultState::EnterToNextState(WindowState* window_state,
527 WindowStateType next_state_type) {
528 // Do nothing if we're already in the same state.
529 if (state_type_ == next_state_type)
530 return;
531
532 WindowStateType previous_state_type = state_type_;
533 state_type_ = next_state_type;
534
535 window_state->UpdateWindowShowStateFromStateType();
536 window_state->NotifyPreStateTypeChange(previous_state_type);
537
538 if (window_state->window()->GetParent()) {
539 if (!window_state->HasRestoreBounds() &&
540 (previous_state_type == WINDOW_STATE_TYPE_DEFAULT ||
541 previous_state_type == WINDOW_STATE_TYPE_NORMAL) &&
542 !window_state->IsMinimized() && !window_state->IsNormalStateType()) {
543 window_state->SaveCurrentBoundsForRestore();
544 }
545
546 // When restoring from a minimized state, we want to restore to the
547 // previous bounds. However, we want to maintain the restore bounds.
548 // (The restore bounds are set if a user maximized the window in one
549 // axis by double clicking the window border for example).
550 gfx::Rect restore_bounds_in_screen;
551 if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED &&
552 window_state->IsNormalStateType() && window_state->HasRestoreBounds() &&
553 !window_state->unminimize_to_restore_bounds()) {
554 restore_bounds_in_screen = window_state->GetRestoreBoundsInScreen();
555 window_state->SaveCurrentBoundsForRestore();
556 }
557
558 if (window_state->IsMaximizedOrFullscreen())
559 MoveToDisplayForRestore(window_state);
560
561 UpdateBoundsFromState(window_state, previous_state_type);
562
563 // Normal state should have no restore bounds unless it's
564 // unminimized.
565 if (!restore_bounds_in_screen.IsEmpty())
566 window_state->SetRestoreBoundsInScreen(restore_bounds_in_screen);
567 else if (window_state->IsNormalStateType())
568 window_state->ClearRestoreBounds();
569 }
570 window_state->NotifyPostStateTypeChange(previous_state_type);
571 }
572
573 void DefaultState::ReenterToCurrentState(
574 WindowState* window_state,
575 WindowState::State* state_in_previous_mode) {
576 WindowStateType previous_state_type = state_in_previous_mode->GetType();
577
578 // A state change should not move a window into or out of full screen since
579 // full screen is a "special mode" the user wanted to be in and should be
580 // respected as such.
581 if (previous_state_type == wm::WINDOW_STATE_TYPE_FULLSCREEN)
582 state_type_ = wm::WINDOW_STATE_TYPE_FULLSCREEN;
583 else if (state_type_ == wm::WINDOW_STATE_TYPE_FULLSCREEN)
584 state_type_ = previous_state_type;
585
586 window_state->UpdateWindowShowStateFromStateType();
587 window_state->NotifyPreStateTypeChange(previous_state_type);
588
589 if ((state_type_ == wm::WINDOW_STATE_TYPE_NORMAL ||
590 state_type_ == wm::WINDOW_STATE_TYPE_DEFAULT) &&
591 !stored_bounds_.IsEmpty()) {
592 // Use the restore mechanism to set the bounds for
593 // the window in normal state. This also covers unminimize case.
594 window_state->SetRestoreBoundsInParent(stored_bounds_);
595 }
596
597 UpdateBoundsFromState(window_state, state_in_previous_mode->GetType());
598
599 // Then restore the restore bounds to their previous value.
600 if (!stored_restore_bounds_.IsEmpty())
601 window_state->SetRestoreBoundsInParent(stored_restore_bounds_);
602 else
603 window_state->ClearRestoreBounds();
604
605 window_state->NotifyPostStateTypeChange(previous_state_type);
606 }
607
608 void DefaultState::UpdateBoundsFromState(WindowState* window_state,
609 WindowStateType previous_state_type) {
610 WmWindow* window = window_state->window();
611 gfx::Rect bounds_in_parent;
612 switch (state_type_) {
613 case WINDOW_STATE_TYPE_LEFT_SNAPPED:
614 case WINDOW_STATE_TYPE_RIGHT_SNAPPED:
615 bounds_in_parent =
616 state_type_ == WINDOW_STATE_TYPE_LEFT_SNAPPED
617 ? GetDefaultLeftSnappedWindowBoundsInParent(window)
618 : GetDefaultRightSnappedWindowBoundsInParent(window);
619 break;
620 case WINDOW_STATE_TYPE_DOCKED: {
621 if (window->GetParent()->GetShellWindowId() !=
622 kShellWindowId_DockedContainer) {
623 WmWindow* docked_container =
624 window->GetRootWindow()->GetChildByShellWindowId(
625 kShellWindowId_DockedContainer);
626 ReparentChildWithTransientChildren(window, window->GetParent(),
627 docked_container);
628 }
629 // Return early because we don't want to update the bounds of the
630 // window below; as the bounds are managed by the dock layout.
631 return;
632 }
633 case WINDOW_STATE_TYPE_DEFAULT:
634 case WINDOW_STATE_TYPE_NORMAL: {
635 gfx::Rect work_area_in_parent = GetDisplayWorkAreaBoundsInParent(window);
636 if (window_state->HasRestoreBounds()) {
637 bounds_in_parent = window_state->GetRestoreBoundsInParent();
638 // Check if the |window|'s restored size is bigger than the working area
639 // This may happen if a window was resized to maximized bounds or if the
640 // display resolution changed while the window was maximized.
641 if (previous_state_type == WINDOW_STATE_TYPE_MAXIMIZED &&
642 bounds_in_parent.width() >= work_area_in_parent.width() &&
643 bounds_in_parent.height() >= work_area_in_parent.height()) {
644 bounds_in_parent = work_area_in_parent;
645 bounds_in_parent.Inset(kMaximizedWindowInset, kMaximizedWindowInset,
646 kMaximizedWindowInset, kMaximizedWindowInset);
647 }
648 } else {
649 bounds_in_parent = window->GetBounds();
650 }
651 // Make sure that part of the window is always visible.
652 wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent,
653 &bounds_in_parent);
654 break;
655 }
656 case WINDOW_STATE_TYPE_MAXIMIZED:
657 bounds_in_parent = GetMaximizedWindowBoundsInParent(window);
658 break;
659
660 case WINDOW_STATE_TYPE_FULLSCREEN:
661 bounds_in_parent = GetDisplayBoundsInParent(window);
662 break;
663
664 case WINDOW_STATE_TYPE_DOCKED_MINIMIZED:
665 case WINDOW_STATE_TYPE_MINIMIZED:
666 break;
667 case WINDOW_STATE_TYPE_INACTIVE:
668 case WINDOW_STATE_TYPE_END:
669 case WINDOW_STATE_TYPE_AUTO_POSITIONED:
670 return;
671 }
672
673 if (!window_state->IsMinimized()) {
674 if (IsMinimizedWindowState(previous_state_type) ||
675 window_state->IsFullscreen()) {
676 window_state->SetBoundsDirect(bounds_in_parent);
677 } else if (window_state->IsMaximized() ||
678 IsMaximizedOrFullscreenWindowStateType(previous_state_type)) {
679 window_state->SetBoundsDirectCrossFade(bounds_in_parent);
680 } else if (window_state->is_dragged()) {
681 // SetBoundsDirectAnimated does not work when the window gets reparented.
682 // TODO(oshima): Consider fixing it and reenable the animation.
683 window_state->SetBoundsDirect(bounds_in_parent);
684 } else {
685 window_state->SetBoundsDirectAnimated(bounds_in_parent);
686 }
687 }
688
689 if (window_state->IsMinimized()) {
690 // Save the previous show state so that we can correctly restore it.
691 window->SetRestoreShowState(ToWindowShowState(previous_state_type));
692 window->SetVisibilityAnimationType(
693 WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
694
695 // Hide the window.
696 window->Hide();
697 // Activate another window.
698 if (window_state->IsActive())
699 window_state->Deactivate();
700 } else if ((window->GetTargetVisibility() ||
701 IsMinimizedWindowState(previous_state_type)) &&
702 !window->GetLayer()->visible()) {
703 // The layer may be hidden if the window was previously minimized. Make
704 // sure it's visible.
705 window->Show();
706 if (IsMinimizedWindowState(previous_state_type) &&
707 !window_state->IsMaximizedOrFullscreen()) {
708 window_state->set_unminimize_to_restore_bounds(false);
709 }
710 }
711 }
712
713 // static
714 void DefaultState::CenterWindow(WindowState* window_state) {
715 if (!window_state->IsNormalOrSnapped())
716 return;
717 WmWindow* window = window_state->window();
718 if (window_state->IsSnapped()) {
719 gfx::Rect center_in_screen = window->GetDisplayNearestWindow().work_area();
720 gfx::Size size = window_state->HasRestoreBounds()
721 ? window_state->GetRestoreBoundsInScreen().size()
722 : window->GetBounds().size();
723 center_in_screen.ClampToCenteredSize(size);
724 window_state->SetRestoreBoundsInScreen(center_in_screen);
725 window_state->Restore();
726 } else {
727 gfx::Rect center_in_parent = GetDisplayWorkAreaBoundsInParent(window);
728 center_in_parent.ClampToCenteredSize(window->GetBounds().size());
729 window_state->SetBoundsDirectAnimated(center_in_parent);
730 }
731 // Centering window is treated as if a user moved and resized the window.
732 window_state->set_bounds_changed_by_user(true);
733 }
734
735 } // namespace wm
736 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/common/default_state.h ('k') | ash/wm/common/default_window_resizer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698