maximize_mode_window_state.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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_state_util.h" 17#include "ash/wm/window_util.h" 18#include "ash/wm/wm_event.h" 19#include "ash/wm/workspace/workspace_window_resizer.h" 20#include "ui/aura/client/aura_constants.h" 21#include "ui/aura/window.h" 22#include "ui/aura/window_delegate.h" 23#include "ui/gfx/display.h" 24#include "ui/gfx/rect.h" 25 26namespace ash { 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() || window_state->CanResize()); 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 centered bounds of the given bounds in the work area. 50gfx::Rect GetCenteredBounds(const gfx::Rect& bounds_in_parent, 51 wm::WindowState* state_object) { 52 gfx::Rect work_area_in_parent = 53 ScreenUtil::GetDisplayWorkAreaBoundsInParent(state_object->window()); 54 work_area_in_parent.ClampToCenteredSize(bounds_in_parent.size()); 55 return work_area_in_parent; 56} 57 58// Returns the maximized/full screen and/or centered bounds of a window. 59gfx::Rect GetBoundsInMaximizedMode(wm::WindowState* state_object) { 60 if (state_object->IsFullscreen()) 61 return ScreenUtil::GetDisplayBoundsInParent(state_object->window()); 62 63 gfx::Rect bounds_in_parent; 64 // Make the window as big as possible. 65 if (state_object->CanMaximize() || state_object->CanResize()) { 66 bounds_in_parent.set_size(GetMaximumSizeOfWindow(state_object)); 67 } else { 68 // We prefer the user given window dimensions over the current windows 69 // dimensions since they are likely to be the result from some other state 70 // object logic. 71 if (state_object->HasRestoreBounds()) 72 bounds_in_parent = state_object->GetRestoreBoundsInParent(); 73 else 74 bounds_in_parent = state_object->window()->bounds(); 75 } 76 return GetCenteredBounds(bounds_in_parent, state_object); 77} 78 79} // namespace 80 81// static 82void MaximizeModeWindowState::UpdateWindowPosition( 83 wm::WindowState* window_state, bool animated) { 84 gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); 85 86 if (bounds_in_parent == window_state->window()->bounds()) 87 return; 88 89 if (animated) 90 window_state->SetBoundsDirect(bounds_in_parent); 91 else 92 window_state->SetBoundsDirectAnimated(bounds_in_parent); 93} 94 95MaximizeModeWindowState::MaximizeModeWindowState( 96 aura::Window* window, MaximizeModeWindowManager* creator) 97 : window_(window), 98 creator_(creator), 99 current_state_type_(wm::GetWindowState(window)->GetStateType()) { 100 old_state_.reset( 101 wm::GetWindowState(window)->SetStateObject( 102 scoped_ptr<State>(this).Pass()).release()); 103} 104 105MaximizeModeWindowState::~MaximizeModeWindowState() { 106 creator_->WindowStateDestroyed(window_); 107} 108 109void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState* window_state) { 110 // Note: When we return we will destroy ourselves with the |our_reference|. 111 scoped_ptr<wm::WindowState::State> our_reference = 112 window_state->SetStateObject(old_state_.Pass()); 113} 114 115void MaximizeModeWindowState::OnWMEvent(wm::WindowState* window_state, 116 const wm::WMEvent* event) { 117 switch (event->type()) { 118 case wm::WM_EVENT_TOGGLE_FULLSCREEN: 119 ToggleFullScreen(window_state, window_state->delegate()); 120 break; 121 case wm::WM_EVENT_FULLSCREEN: 122 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN, true); 123 break; 124 case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: 125 case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: 126 case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: 127 case wm::WM_EVENT_TOGGLE_MAXIMIZE: 128 case wm::WM_EVENT_CENTER: 129 case wm::WM_EVENT_SNAP_LEFT: 130 case wm::WM_EVENT_SNAP_RIGHT: 131 case wm::WM_EVENT_NORMAL: 132 case wm::WM_EVENT_MAXIMIZE: 133 UpdateWindow(window_state, 134 GetMaximizedOrCenteredWindowType(window_state), 135 true); 136 return; 137 case wm::WM_EVENT_MINIMIZE: 138 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED, true); 139 return; 140 case wm::WM_EVENT_SHOW_INACTIVE: 141 return; 142 case wm::WM_EVENT_SET_BOUNDS: 143 if (window_state->CanResize()) { 144 // In case the window is resizable and / or maximized we ignore the 145 // requested bounds change and resize to the biggest possible size. 146 UpdateBounds(window_state, true); 147 } else 148 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && 149 current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED) { 150 // In all other cases (except for minimized windows) we respect the 151 // requested bounds and center it to a fully visible area on the screen. 152 gfx::Rect bounds_in_parent = 153 (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); 154 bounds_in_parent = GetCenteredBounds(bounds_in_parent, window_state); 155 if (bounds_in_parent != window_state->window()->bounds()) { 156 if (window_state->window()->IsVisible()) 157 window_state->SetBoundsDirectAnimated(bounds_in_parent); 158 else 159 window_state->SetBoundsDirect(bounds_in_parent); 160 } 161 } 162 break; 163 case wm::WM_EVENT_ADDED_TO_WORKSPACE: 164 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && 165 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && 166 current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) { 167 wm::WindowStateType new_state = 168 GetMaximizedOrCenteredWindowType(window_state); 169 UpdateWindow(window_state, new_state, true); 170 } 171 break; 172 case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED: 173 case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED: 174 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) 175 UpdateBounds(window_state, true); 176 break; 177 } 178} 179 180wm::WindowStateType MaximizeModeWindowState::GetType() const { 181 return current_state_type_; 182} 183 184void MaximizeModeWindowState::AttachState( 185 wm::WindowState* window_state, 186 wm::WindowState::State* previous_state) { 187 current_state_type_ = previous_state->GetType(); 188 189 // Initialize the state to a good preset. 190 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && 191 current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && 192 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) { 193 UpdateWindow(window_state, 194 GetMaximizedOrCenteredWindowType(window_state), 195 true); 196 } 197 198 window_state->set_can_be_dragged(false); 199} 200 201void MaximizeModeWindowState::DetachState(wm::WindowState* window_state) { 202 window_state->set_can_be_dragged(true); 203} 204 205void MaximizeModeWindowState::UpdateWindow(wm::WindowState* window_state, 206 wm::WindowStateType target_state, 207 bool animated) { 208 DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED || 209 target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED || 210 (target_state == wm::WINDOW_STATE_TYPE_NORMAL && 211 !window_state->CanMaximize()) || 212 target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN); 213 214 if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) { 215 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED) 216 return; 217 218 current_state_type_ = target_state; 219 ::wm::SetWindowVisibilityAnimationType( 220 window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); 221 window_state->window()->Hide(); 222 if (window_state->IsActive()) 223 window_state->Deactivate(); 224 return; 225 } 226 227 if (current_state_type_ == target_state) { 228 // If the state type did not change, update it accordingly. 229 UpdateBounds(window_state, animated); 230 return; 231 } 232 233 const wm::WindowStateType old_state_type = current_state_type_; 234 current_state_type_ = target_state; 235 window_state->UpdateWindowShowStateFromStateType(); 236 window_state->NotifyPreStateTypeChange(old_state_type); 237 UpdateBounds(window_state, animated); 238 window_state->NotifyPostStateTypeChange(old_state_type); 239 240 if ((window_state->window()->TargetVisibility() || 241 old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) && 242 !window_state->window()->layer()->visible()) { 243 // The layer may be hidden if the window was previously minimized. Make 244 // sure it's visible. 245 window_state->window()->Show(); 246 } 247} 248 249wm::WindowStateType MaximizeModeWindowState::GetMaximizedOrCenteredWindowType( 250 wm::WindowState* window_state) { 251 return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED : 252 wm::WINDOW_STATE_TYPE_NORMAL; 253} 254 255void MaximizeModeWindowState::UpdateBounds(wm::WindowState* window_state, 256 bool animated) { 257 gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); 258 // If we have a target bounds rectangle, we center it and set it 259 // accordingly. 260 if (!bounds_in_parent.IsEmpty() && 261 bounds_in_parent != window_state->window()->bounds()) { 262 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED || 263 !window_state->window()->IsVisible() || 264 !animated) { 265 window_state->SetBoundsDirect(bounds_in_parent); 266 } else { 267 window_state->SetBoundsDirectAnimated(bounds_in_parent); 268 } 269 } 270} 271 272} // namespace ash 273