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/lock_window_state.h"
6
7#include "ash/screen_util.h"
8#include "ash/shell.h"
9#include "ash/wm/lock_layout_manager.h"
10#include "ash/wm/window_animations.h"
11#include "ash/wm/window_state.h"
12#include "ash/wm/window_state_delegate.h"
13#include "ash/wm/window_state_util.h"
14#include "ash/wm/window_util.h"
15#include "ash/wm/wm_event.h"
16#include "ui/aura/window.h"
17#include "ui/aura/window_delegate.h"
18#include "ui/gfx/rect.h"
19#include "ui/keyboard/keyboard_controller.h"
20#include "ui/keyboard/keyboard_util.h"
21#include "ui/wm/core/window_animations.h"
22
23namespace ash {
24
25LockWindowState::LockWindowState(aura::Window* window)
26    : current_state_type_(wm::GetWindowState(window)->GetStateType()) {
27}
28
29LockWindowState::~LockWindowState() {
30}
31
32void LockWindowState::OnWMEvent(wm::WindowState* window_state,
33                                const wm::WMEvent* event) {
34  aura::Window* window = window_state->window();
35  gfx::Rect bounds = window->bounds();
36
37  switch (event->type()) {
38    case wm::WM_EVENT_TOGGLE_FULLSCREEN:
39      ToggleFullScreen(window_state, window_state->delegate());
40      break;
41    case wm::WM_EVENT_FULLSCREEN:
42      UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN);
43      break;
44    case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
45    case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
46    case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
47    case wm::WM_EVENT_TOGGLE_MAXIMIZE:
48    case wm::WM_EVENT_CENTER:
49    case wm::WM_EVENT_SNAP_LEFT:
50    case wm::WM_EVENT_SNAP_RIGHT:
51    case wm::WM_EVENT_NORMAL:
52    case wm::WM_EVENT_MAXIMIZE:
53      UpdateWindow(window_state,
54                   GetMaximizedOrCenteredWindowType(window_state));
55      return;
56    case wm::WM_EVENT_MINIMIZE:
57      UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED);
58      return;
59    case wm::WM_EVENT_SHOW_INACTIVE:
60      return;
61    case wm::WM_EVENT_SET_BOUNDS:
62      if (window_state->IsMaximized() || window_state->IsFullscreen()) {
63        UpdateBounds(window_state);
64      } else {
65        const ash::wm::SetBoundsEvent* bounds_event =
66            static_cast<const ash::wm::SetBoundsEvent*>(event);
67        window_state->SetBoundsConstrained(bounds_event->requested_bounds());
68      }
69      break;
70    case wm::WM_EVENT_ADDED_TO_WORKSPACE:
71      if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED &&
72          current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED &&
73          current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) {
74        UpdateWindow(window_state,
75                     GetMaximizedOrCenteredWindowType(window_state));
76      }
77      break;
78    case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED:
79    case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED:
80      UpdateBounds(window_state);
81      break;
82  }
83}
84
85wm::WindowStateType LockWindowState::GetType() const {
86  return current_state_type_;
87}
88
89void LockWindowState::AttachState(wm::WindowState* window_state,
90                                  wm::WindowState::State* previous_state) {
91  current_state_type_ = previous_state->GetType();
92
93  // Initialize the state to a good preset.
94  if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED &&
95      current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED &&
96      current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) {
97    UpdateWindow(window_state,
98                 GetMaximizedOrCenteredWindowType(window_state));
99  }
100}
101
102void LockWindowState::DetachState(wm::WindowState* window_state) {
103}
104
105// static
106wm::WindowState* LockWindowState::SetLockWindowState(aura::Window* window) {
107  scoped_ptr<wm::WindowState::State> lock_state(new LockWindowState(window));
108  scoped_ptr<wm::WindowState::State> old_state(
109      wm::GetWindowState(window)->SetStateObject(lock_state.Pass()));
110  return wm::GetWindowState(window);
111}
112
113void LockWindowState::UpdateWindow(wm::WindowState* window_state,
114                                   wm::WindowStateType target_state) {
115  DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED ||
116         target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED ||
117         (target_state == wm::WINDOW_STATE_TYPE_NORMAL &&
118              !window_state->CanMaximize()) ||
119         target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN);
120
121  if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) {
122    if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED)
123      return;
124
125    current_state_type_ = target_state;
126    ::wm::SetWindowVisibilityAnimationType(
127        window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
128    window_state->window()->Hide();
129    if (window_state->IsActive())
130      window_state->Deactivate();
131    return;
132  }
133
134  if (current_state_type_ == target_state) {
135    // If the state type did not change, update it accordingly.
136    UpdateBounds(window_state);
137    return;
138  }
139
140  const wm::WindowStateType old_state_type = current_state_type_;
141  current_state_type_ = target_state;
142  window_state->UpdateWindowShowStateFromStateType();
143  window_state->NotifyPreStateTypeChange(old_state_type);
144  UpdateBounds(window_state);
145  window_state->NotifyPostStateTypeChange(old_state_type);
146
147  if ((window_state->window()->TargetVisibility() ||
148      old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) &&
149      !window_state->window()->layer()->visible()) {
150    // The layer may be hidden if the window was previously minimized. Make
151    // sure it's visible.
152    window_state->window()->Show();
153  }
154}
155
156wm::WindowStateType LockWindowState::GetMaximizedOrCenteredWindowType(
157      wm::WindowState* window_state) {
158  return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED :
159                                       wm::WINDOW_STATE_TYPE_NORMAL;
160}
161
162void LockWindowState::UpdateBounds(wm::WindowState* window_state) {
163  if (!window_state->IsMaximized() && !window_state->IsFullscreen())
164    return;
165
166  keyboard::KeyboardController* keyboard_controller =
167      keyboard::KeyboardController::GetInstance();
168  gfx::Rect keyboard_bounds;
169
170  if (keyboard_controller &&
171      !keyboard::IsKeyboardOverscrollEnabled() &&
172      keyboard_controller->keyboard_visible()) {
173    keyboard_bounds = keyboard_controller->current_keyboard_bounds();
174  }
175
176  gfx::Rect bounds =
177      ScreenUtil::GetDisplayBoundsInParent(window_state->window());
178  bounds.set_height(bounds.height() - keyboard_bounds.height());
179
180  VLOG(1) << "Updating window bounds to: " << bounds.ToString();
181  window_state->SetBoundsDirect(bounds);
182}
183
184}  // namespace ash
185