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

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

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

Powered by Google App Engine
This is Rietveld 408576698