Home | History | Annotate | Download | only in wm
      1 // Copyright 2013 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/window_state.h"
      6 
      7 #include "ash/ash_switches.h"
      8 #include "ash/root_window_controller.h"
      9 #include "ash/screen_ash.h"
     10 #include "ash/shell_window_ids.h"
     11 #include "ash/wm/window_properties.h"
     12 #include "ash/wm/window_state_delegate.h"
     13 #include "ash/wm/window_state_observer.h"
     14 #include "ash/wm/window_util.h"
     15 #include "ash/wm/wm_types.h"
     16 #include "base/auto_reset.h"
     17 #include "base/command_line.h"
     18 #include "ui/aura/client/aura_constants.h"
     19 #include "ui/aura/window.h"
     20 #include "ui/aura/window_delegate.h"
     21 #include "ui/gfx/display.h"
     22 #include "ui/views/corewm/window_util.h"
     23 
     24 namespace ash {
     25 namespace wm {
     26 
     27 // static
     28 bool WindowState::IsMaximizedOrFullscreenState(ui::WindowShowState show_state) {
     29   return show_state == ui::SHOW_STATE_FULLSCREEN ||
     30       show_state == ui::SHOW_STATE_MAXIMIZED;
     31 }
     32 
     33 WindowState::WindowState(aura::Window* window)
     34     : window_(window),
     35       window_position_managed_(false),
     36       bounds_changed_by_user_(false),
     37       panel_attached_(true),
     38       continue_drag_after_reparent_(false),
     39       ignored_by_shelf_(false),
     40       can_consume_system_keys_(false),
     41       top_row_keys_are_function_keys_(false),
     42       window_resizer_(NULL),
     43       always_restores_to_restore_bounds_(false),
     44       hide_shelf_when_fullscreen_(true),
     45       animate_to_fullscreen_(true),
     46       minimum_visibility_(false),
     47       in_set_window_show_type_(false),
     48       window_show_type_(ToWindowShowType(GetShowState())) {
     49   window_->AddObserver(this);
     50 
     51 #if defined(OS_CHROMEOS)
     52   // NOTE(pkotwicz): Animating to immersive fullscreen does not look good. When
     53   // the kAshEnableImmersiveFullscreenForAllWindows flag is set most windows
     54   // can be put into immersive fullscreen. It is not worth the added complexity
     55   // to only animate to fullscreen if the window is put into immersive
     56   // fullscreen.
     57   animate_to_fullscreen_ = !CommandLine::ForCurrentProcess()->HasSwitch(
     58       switches::kAshEnableImmersiveFullscreenForAllWindows);
     59 #endif
     60 }
     61 
     62 WindowState::~WindowState() {
     63 }
     64 
     65 bool WindowState::HasDelegate() const {
     66   return delegate_;
     67 }
     68 
     69 void WindowState::SetDelegate(scoped_ptr<WindowStateDelegate> delegate) {
     70   DCHECK(!delegate_.get());
     71   delegate_ = delegate.Pass();
     72 }
     73 
     74 ui::WindowShowState WindowState::GetShowState() const {
     75   return window_->GetProperty(aura::client::kShowStateKey);
     76 }
     77 
     78 bool WindowState::IsMinimized() const {
     79   return GetShowState() == ui::SHOW_STATE_MINIMIZED;
     80 }
     81 
     82 bool WindowState::IsMaximized() const {
     83   return GetShowState() == ui::SHOW_STATE_MAXIMIZED;
     84 }
     85 
     86 bool WindowState::IsFullscreen() const {
     87   return GetShowState() == ui::SHOW_STATE_FULLSCREEN;
     88 }
     89 
     90 bool WindowState::IsMaximizedOrFullscreen() const {
     91   return IsMaximizedOrFullscreenState(GetShowState());
     92 }
     93 
     94 bool WindowState::IsNormalShowState() const {
     95   ui::WindowShowState state = window_->GetProperty(aura::client::kShowStateKey);
     96   return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT;
     97 }
     98 
     99 bool WindowState::IsActive() const {
    100   return IsActiveWindow(window_);
    101 }
    102 
    103 bool WindowState::IsDocked() const {
    104   return window_->parent() &&
    105       window_->parent()->id() == internal::kShellWindowId_DockedContainer;
    106 }
    107 
    108 bool WindowState::IsSnapped() const {
    109   return window_show_type_ == SHOW_TYPE_LEFT_SNAPPED ||
    110       window_show_type_ == SHOW_TYPE_RIGHT_SNAPPED;
    111 }
    112 
    113 bool WindowState::CanMaximize() const {
    114   return window_->GetProperty(aura::client::kCanMaximizeKey);
    115 }
    116 
    117 bool WindowState::CanMinimize() const {
    118   internal::RootWindowController* controller =
    119       internal::RootWindowController::ForWindow(window_);
    120   if (!controller)
    121     return false;
    122   aura::Window* lockscreen = controller->GetContainer(
    123       internal::kShellWindowId_LockScreenContainersContainer);
    124   if (lockscreen->Contains(window_))
    125     return false;
    126 
    127   return true;
    128 }
    129 
    130 bool WindowState::CanResize() const {
    131   return window_->GetProperty(aura::client::kCanResizeKey);
    132 }
    133 
    134 bool WindowState::CanActivate() const {
    135   return views::corewm::CanActivateWindow(window_);
    136 }
    137 
    138 bool WindowState::CanSnap() const {
    139   if (!CanResize() ||
    140       window_->type() == aura::client::WINDOW_TYPE_PANEL ||
    141       window_->transient_parent())
    142     return false;
    143   // If a window has a maximum size defined, snapping may make it too big.
    144   return window_->delegate() ? window_->delegate()->GetMaximumSize().IsEmpty() :
    145                               true;
    146 }
    147 
    148 bool WindowState::HasRestoreBounds() const {
    149   return window_->GetProperty(aura::client::kRestoreBoundsKey) != NULL;
    150 }
    151 
    152 void WindowState::Maximize() {
    153   window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    154 }
    155 
    156 void WindowState::SnapLeft(const gfx::Rect& bounds) {
    157   SnapWindow(SHOW_TYPE_LEFT_SNAPPED, bounds);
    158 }
    159 
    160 void WindowState::SnapRight(const gfx::Rect& bounds) {
    161   SnapWindow(SHOW_TYPE_RIGHT_SNAPPED, bounds);
    162 }
    163 
    164 void WindowState::Minimize() {
    165   window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    166 }
    167 
    168 void WindowState::Unminimize() {
    169   window_->SetProperty(
    170       aura::client::kShowStateKey,
    171       window_->GetProperty(aura::client::kRestoreShowStateKey));
    172   window_->ClearProperty(aura::client::kRestoreShowStateKey);
    173 }
    174 
    175 void WindowState::Activate() {
    176   ActivateWindow(window_);
    177 }
    178 
    179 void WindowState::Deactivate() {
    180   DeactivateWindow(window_);
    181 }
    182 
    183 void WindowState::Restore() {
    184   window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    185 }
    186 
    187 void WindowState::ToggleMaximized() {
    188   if (IsMaximized())
    189     Restore();
    190   else if (CanMaximize())
    191     Maximize();
    192 }
    193 
    194 void WindowState::ToggleFullscreen() {
    195   // Window which cannot be maximized should not be fullscreened.
    196   // It can, however, be restored if it was fullscreened.
    197   bool is_fullscreen = IsFullscreen();
    198   if (!is_fullscreen && !CanMaximize())
    199     return;
    200   if (delegate_ && delegate_->ToggleFullscreen(this))
    201     return;
    202   if (is_fullscreen) {
    203     Restore();
    204   } else {
    205     window_->SetProperty(aura::client::kShowStateKey,
    206                          ui::SHOW_STATE_FULLSCREEN);
    207   }
    208 }
    209 
    210 void WindowState::SetBoundsInScreen(
    211     const gfx::Rect& bounds_in_screen) {
    212   gfx::Rect bounds_in_parent =
    213       ScreenAsh::ConvertRectFromScreen(window_->parent(),
    214                                        bounds_in_screen);
    215   window_->SetBounds(bounds_in_parent);
    216 }
    217 
    218 void WindowState::SaveCurrentBoundsForRestore() {
    219   gfx::Rect bounds_in_screen =
    220       ScreenAsh::ConvertRectToScreen(window_->parent(),
    221                                      window_->bounds());
    222   SetRestoreBoundsInScreen(bounds_in_screen);
    223 }
    224 
    225 gfx::Rect WindowState::GetRestoreBoundsInScreen() const {
    226   return *window_->GetProperty(aura::client::kRestoreBoundsKey);
    227 }
    228 
    229 gfx::Rect WindowState::GetRestoreBoundsInParent() const {
    230   return ScreenAsh::ConvertRectFromScreen(window_->parent(),
    231                                           GetRestoreBoundsInScreen());
    232 }
    233 
    234 void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) {
    235   window_->SetProperty(aura::client::kRestoreBoundsKey, new gfx::Rect(bounds));
    236 }
    237 
    238 void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) {
    239   SetRestoreBoundsInScreen(
    240       ScreenAsh::ConvertRectToScreen(window_->parent(), bounds));
    241 }
    242 
    243 void WindowState::ClearRestoreBounds() {
    244   window_->ClearProperty(aura::client::kRestoreBoundsKey);
    245 }
    246 
    247 void WindowState::SetPreAutoManageWindowBounds(
    248     const gfx::Rect& bounds) {
    249   pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds));
    250 }
    251 
    252 void WindowState::AddObserver(WindowStateObserver* observer) {
    253   observer_list_.AddObserver(observer);
    254 }
    255 
    256 void WindowState::RemoveObserver(WindowStateObserver* observer) {
    257   observer_list_.RemoveObserver(observer);
    258 }
    259 
    260 void WindowState::OnWindowPropertyChanged(aura::Window* window,
    261                                           const void* key,
    262                                           intptr_t old) {
    263   DCHECK_EQ(window, window_);
    264   if (key == aura::client::kShowStateKey)
    265     SetWindowShowType(ToWindowShowType(GetShowState()));
    266 }
    267 
    268 void WindowState::SnapWindow(WindowShowType left_or_right,
    269                              const gfx::Rect& bounds) {
    270   if (window_show_type_ == left_or_right) {
    271     window_->SetBounds(bounds);
    272     return;
    273   }
    274 
    275   // Compute the bounds that the window will restore to. If the window does not
    276   // already have restore bounds, it will be restored (when un-snapped) to the
    277   // last bounds that it had before getting snapped.
    278   gfx::Rect restore_bounds_in_screen(HasRestoreBounds() ?
    279       GetRestoreBoundsInScreen() : window_->GetBoundsInScreen());
    280   // Set the window's restore bounds so that WorkspaceLayoutManager knows
    281   // which width to use when the snapped window is moved to the edge.
    282   SetRestoreBoundsInParent(bounds);
    283 
    284   bool was_maximized = IsMaximizedOrFullscreen();
    285   // Before we can set the bounds we need to restore the window.
    286   // Restoring the window will set the window to its restored bounds set above.
    287   // Restore will cause OnWindowPropertyChanged() so it needs to be done
    288   // before notifying that the WindowShowType has changed to |left_or_right|.
    289   if (was_maximized)
    290     Restore();
    291   DCHECK(left_or_right == SHOW_TYPE_LEFT_SNAPPED ||
    292          left_or_right == SHOW_TYPE_RIGHT_SNAPPED);
    293   SetWindowShowType(left_or_right);
    294   // TODO(varkha): Ideally the bounds should be changed in a LayoutManager upon
    295   // observing the WindowShowType change.
    296   // If the window is a child of kShellWindowId_DockedContainer such as during
    297   // a drag, the window's bounds are not set in
    298   // WorkspaceLayoutManager::OnWindowShowTypeChanged(). Set them here. Skip
    299   // setting the bounds otherwise to avoid stopping the slide animation which
    300   // was started as a result of OnWindowShowTypeChanged().
    301   if (IsDocked())
    302     window_->SetBounds(bounds);
    303   SetRestoreBoundsInScreen(restore_bounds_in_screen);
    304 }
    305 
    306 void WindowState::SetWindowShowType(WindowShowType new_window_show_type) {
    307   if (in_set_window_show_type_)
    308     return;
    309   base::AutoReset<bool> resetter(&in_set_window_show_type_, true);
    310 
    311   ui::WindowShowState new_window_state =
    312       ToWindowShowState(new_window_show_type);
    313   if (new_window_state != GetShowState())
    314     window_->SetProperty(aura::client::kShowStateKey, new_window_state);
    315   WindowShowType old_window_show_type = window_show_type_;
    316   window_show_type_ = new_window_show_type;
    317   if (old_window_show_type != window_show_type_) {
    318     FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
    319                       OnWindowShowTypeChanged(this, old_window_show_type));
    320   }
    321 }
    322 
    323 WindowState* GetActiveWindowState() {
    324   aura::Window* active = GetActiveWindow();
    325   return active ? GetWindowState(active) : NULL;
    326 }
    327 
    328 WindowState* GetWindowState(aura::Window* window) {
    329   if (!window)
    330     return NULL;
    331   WindowState* settings = window->GetProperty(internal::kWindowStateKey);
    332   if(!settings) {
    333     settings = new WindowState(window);
    334     window->SetProperty(internal::kWindowStateKey, settings);
    335   }
    336   return settings;
    337 }
    338 
    339 const WindowState* GetWindowState(const aura::Window* window) {
    340   return GetWindowState(const_cast<aura::Window*>(window));
    341 }
    342 
    343 }  // namespace wm
    344 }  // namespace ash
    345