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

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

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

Powered by Google App Engine
This is Rietveld 408576698