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