maximize_mode_window_state.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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/maximize_mode/maximize_mode_window_state.h"
6
7#include "ash/display/display_controller.h"
8#include "ash/screen_util.h"
9#include "ash/shell.h"
10#include "ash/shell_window_ids.h"
11#include "ash/wm/coordinate_conversion.h"
12#include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
13#include "ash/wm/window_animations.h"
14#include "ash/wm/window_state.h"
15#include "ash/wm/window_state_delegate.h"
16#include "ash/wm/window_util.h"
17#include "ash/wm/wm_event.h"
18#include "ash/wm/workspace/workspace_window_resizer.h"
19#include "ui/aura/client/aura_constants.h"
20#include "ui/aura/window.h"
21#include "ui/aura/window_delegate.h"
22#include "ui/gfx/display.h"
23#include "ui/gfx/rect.h"
24
25namespace ash {
26namespace internal {
27namespace {
28
29// Returns the biggest possible size for a window which is about to be
30// maximized.
31gfx::Size GetMaximumSizeOfWindow(wm::WindowState* window_state) {
32  DCHECK(window_state->CanMaximize());
33
34  gfx::Size workspace_size = ScreenUtil::GetMaximizedWindowBoundsInParent(
35      window_state->window()).size();
36
37  aura::WindowDelegate* delegate = window_state->window()->delegate();
38  if (!delegate)
39    return workspace_size;
40
41  gfx::Size size = delegate->GetMaximumSize();
42  if (size.IsEmpty())
43    return workspace_size;
44
45  size.SetToMin(workspace_size);
46  return size;
47}
48
49// Returns the maximized and centered bounds of a window.
50gfx::Rect GetMaximizedAndCenteredBounds(wm::WindowState* state_object) {
51  gfx::Rect bounds_in_parent;
52  if (state_object->CanMaximize()) {
53    bounds_in_parent.set_size(GetMaximumSizeOfWindow(state_object));
54  } else {
55    // We prefer the user given window dimensions over the current windows
56    // dimensions since they are likely to be the result from some other state
57    // object logic.
58    if (state_object->HasRestoreBounds())
59      bounds_in_parent = state_object->GetRestoreBoundsInParent();
60    else
61      bounds_in_parent = state_object->window()->bounds();
62  }
63  gfx::Rect work_area_in_parent =
64      ScreenUtil::GetDisplayWorkAreaBoundsInParent(state_object->window());
65
66  wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent,
67                                                  &bounds_in_parent);
68
69  // Center the window over the work area.
70  int x = (work_area_in_parent.width() - bounds_in_parent.width()) / 2 +
71          work_area_in_parent.x();
72  int y = (work_area_in_parent.height() - bounds_in_parent.height()) / 2 +
73          work_area_in_parent.y();
74
75  bounds_in_parent.set_origin(gfx::Point(x, y));
76
77  return bounds_in_parent;
78}
79
80}  // namespace
81
82// static
83void MaximizeModeWindowState::UpdateWindowPosition(
84    wm::WindowState* window_state, bool animated) {
85  gfx::Rect bounds_in_parent = GetMaximizedAndCenteredBounds(window_state);
86
87  if (bounds_in_parent == window_state->window()->bounds())
88    return;
89
90  if (animated)
91    window_state->SetBoundsDirect(bounds_in_parent);
92  else
93    window_state->SetBoundsDirectAnimated(bounds_in_parent);
94}
95
96MaximizeModeWindowState::MaximizeModeWindowState(
97    aura::Window* window, MaximizeModeWindowManager* creator)
98    : window_(window),
99      creator_(creator),
100      current_state_type_(wm::GetWindowState(window)->GetStateType()) {
101  old_state_.reset(
102      wm::GetWindowState(window)->SetStateObject(
103          scoped_ptr<State>(this).Pass()).release());
104}
105
106MaximizeModeWindowState::~MaximizeModeWindowState() {
107  creator_->WindowStateDestroyed(window_);
108}
109
110void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState* window_state) {
111  // Note: When we return we will destroy ourselves with the |our_reference|.
112  scoped_ptr<wm::WindowState::State> our_reference =
113      window_state->SetStateObject(old_state_.Pass());
114}
115
116void MaximizeModeWindowState::OnWMEvent(wm::WindowState* window_state,
117                                        const wm::WMEvent* event) {
118  switch (event->type()) {
119    case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
120    case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
121    case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
122    case wm::WM_EVENT_TOGGLE_FULLSCREEN:
123    case wm::WM_EVENT_TOGGLE_MAXIMIZE:
124    case wm::WM_EVENT_CENTER:
125    case wm::WM_EVENT_FULLSCREEN:
126    case wm::WM_EVENT_SNAP_LEFT:
127    case wm::WM_EVENT_SNAP_RIGHT:
128    case wm::WM_EVENT_NORMAL:
129    case wm::WM_EVENT_MAXIMIZE:
130      MaximizeOrCenterWindow(window_state, true);
131      return;
132    case wm::WM_EVENT_MINIMIZE:
133      if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) {
134        current_state_type_ = wm::WINDOW_STATE_TYPE_MINIMIZED;
135        window_state->Minimize();
136      }
137      return;
138    case wm::WM_EVENT_SHOW_INACTIVE:
139      return;
140    case wm::WM_EVENT_SET_BOUNDS:
141      if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED &&
142          current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED) {
143        gfx::Rect bounds_in_parent =
144            (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds();
145        bounds_in_parent.ClampToCenteredSize(
146             ScreenUtil::GetDisplayWorkAreaBoundsInParent(
147                 window_state->window()).size());
148        if (bounds_in_parent != window_state->window()->bounds())
149          window_state->SetBoundsDirectAnimated(bounds_in_parent);
150      }
151      break;
152    case wm::WM_EVENT_ADDED_TO_WORKSPACE:
153      MaximizeOrCenterWindow(window_state, true);
154      break;
155    case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED:
156    case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED:
157      if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED)
158        MaximizeOrCenterWindow(window_state, false);
159      break;
160  }
161}
162
163wm::WindowStateType MaximizeModeWindowState::GetType() const {
164  return current_state_type_;
165}
166
167void MaximizeModeWindowState::AttachState(
168    wm::WindowState* window_state,
169    wm::WindowState::State* previous_state) {
170  current_state_type_ = previous_state->GetType();
171
172  // Initialize the state to a good preset.
173  if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED &&
174      current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) {
175    MaximizeOrCenterWindow(window_state, true);
176  }
177
178  window_state->set_can_be_dragged(false);
179}
180
181void MaximizeModeWindowState::DetachState(wm::WindowState* window_state) {
182  window_state->set_can_be_dragged(true);
183}
184
185void MaximizeModeWindowState::MaximizeOrCenterWindow(
186    wm::WindowState* window_state,
187    bool animated) {
188  const wm::WindowStateType target_state =
189      window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED :
190                                    wm::WINDOW_STATE_TYPE_NORMAL;
191  const wm::WindowStateType old_state_type = current_state_type_;
192  gfx::Rect bounds_in_parent = GetMaximizedAndCenteredBounds(window_state);
193
194  if (current_state_type_ != target_state) {
195    current_state_type_ = target_state;
196    window_state->UpdateWindowShowStateFromStateType();
197    window_state->NotifyPreStateTypeChange(old_state_type);
198    // If we have a target bounds rectangle, we center it and set it
199    // accordingly.
200    if (!bounds_in_parent.IsEmpty()) {
201      if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED || !animated)
202        window_state->SetBoundsDirect(bounds_in_parent);
203      else
204        window_state->SetBoundsDirectAnimated(bounds_in_parent);
205    }
206    window_state->NotifyPostStateTypeChange(old_state_type);
207  } else if (!bounds_in_parent.IsEmpty() &&
208             bounds_in_parent != window_state->window()->bounds()) {
209    // Coming here, we were most probably called through a display change.
210    // Do not animate.
211    if (animated)
212      window_state->SetBoundsDirectAnimated(bounds_in_parent);
213    else
214      window_state->SetBoundsDirect(bounds_in_parent);
215  }
216
217  if ((window_state->window()->TargetVisibility() ||
218      old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) &&
219      !window_state->window()->layer()->visible()) {
220    // The layer may be hidden if the window was previously minimized. Make
221    // sure it's visible.
222    window_state->window()->Show();
223  }
224}
225
226}  // namespace internal
227}  // namespace ash
228