immersive_mode_controller_ash.cc revision 010d83a9304c5a91596085d917d248abff47903a
1// Copyright 2012 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 "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" 6 7#include "ash/shell.h" 8#include "ash/wm/window_state.h" 9#include "chrome/browser/chrome_notification_types.h" 10#include "chrome/browser/ui/fullscreen/fullscreen_controller.h" 11#include "chrome/browser/ui/views/frame/browser_view.h" 12#include "chrome/browser/ui/views/frame/top_container_view.h" 13#include "chrome/browser/ui/views/tabs/tab_strip.h" 14#include "content/public/browser/notification_service.h" 15#include "content/public/browser/web_contents.h" 16#include "ui/aura/window.h" 17#include "ui/views/view.h" 18#include "ui/views/widget/widget.h" 19#include "ui/views/window/non_client_view.h" 20 21namespace { 22 23// Revealing the TopContainerView looks better if the animation starts and ends 24// just a few pixels before the view goes offscreen, which reduces the visual 25// "pop" as the 3-pixel tall "light bar" style tab strip becomes visible. 26const int kAnimationOffsetY = 3; 27 28// Converts from ImmersiveModeController::AnimateReveal to 29// ash::ImmersiveFullscreenController::AnimateReveal. 30ash::ImmersiveFullscreenController::AnimateReveal 31ToImmersiveFullscreenControllerAnimateReveal( 32 ImmersiveModeController::AnimateReveal animate_reveal) { 33 switch (animate_reveal) { 34 case ImmersiveModeController::ANIMATE_REVEAL_YES: 35 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_YES; 36 case ImmersiveModeController::ANIMATE_REVEAL_NO: 37 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; 38 } 39 NOTREACHED(); 40 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; 41} 42 43} // namespace 44 45ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() 46 : controller_(new ash::ImmersiveFullscreenController), 47 browser_view_(NULL), 48 native_window_(NULL), 49 observers_enabled_(false), 50 use_tab_indicators_(false), 51 visible_fraction_(1) { 52} 53 54ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { 55 EnableWindowObservers(false); 56} 57 58void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { 59 browser_view_ = browser_view; 60 native_window_ = browser_view_->GetNativeWindow(); 61 controller_->Init(this, browser_view_->frame(), 62 browser_view_->top_container()); 63} 64 65void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { 66 if (controller_->IsEnabled() == enabled) 67 return; 68 69 EnableWindowObservers(enabled); 70 71 controller_->SetEnabled(browser_view_->browser()->is_app() ? 72 ash::ImmersiveFullscreenController::WINDOW_TYPE_HOSTED_APP : 73 ash::ImmersiveFullscreenController::WINDOW_TYPE_BROWSER 74 , enabled); 75} 76 77bool ImmersiveModeControllerAsh::IsEnabled() const { 78 return controller_->IsEnabled(); 79} 80 81bool ImmersiveModeControllerAsh::ShouldHideTabIndicators() const { 82 return !use_tab_indicators_; 83} 84 85bool ImmersiveModeControllerAsh::ShouldHideTopViews() const { 86 return controller_->IsEnabled() && !controller_->IsRevealed(); 87} 88 89bool ImmersiveModeControllerAsh::IsRevealed() const { 90 return controller_->IsRevealed(); 91} 92 93int ImmersiveModeControllerAsh::GetTopContainerVerticalOffset( 94 const gfx::Size& top_container_size) const { 95 if (!IsEnabled()) 96 return 0; 97 98 // The TopContainerView is flush with the top of |browser_view_| when the 99 // top-of-window views are fully closed so that when the tab indicators are 100 // used, the "light bar" style tab strip is flush with the top of 101 // |browser_view_|. 102 if (!IsRevealed()) 103 return 0; 104 105 int height = top_container_size.height() - kAnimationOffsetY; 106 return static_cast<int>(height * (visible_fraction_ - 1)); 107} 108 109ImmersiveRevealedLock* ImmersiveModeControllerAsh::GetRevealedLock( 110 AnimateReveal animate_reveal) { 111 return controller_->GetRevealedLock( 112 ToImmersiveFullscreenControllerAnimateReveal(animate_reveal)); 113} 114 115void ImmersiveModeControllerAsh::OnFindBarVisibleBoundsChanged( 116 const gfx::Rect& new_visible_bounds_in_screen) { 117 find_bar_visible_bounds_in_screen_ = new_visible_bounds_in_screen; 118} 119 120void ImmersiveModeControllerAsh::SetupForTest() { 121 controller_->SetupForTest(); 122} 123 124void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { 125 if (observers_enabled_ == enable) 126 return; 127 observers_enabled_ = enable; 128 129 content::Source<FullscreenController> source( 130 browser_view_->browser()->fullscreen_controller()); 131 if (enable) { 132 ash::wm::GetWindowState(native_window_)->AddObserver(this); 133 registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); 134 } else { 135 ash::wm::GetWindowState(native_window_)->RemoveObserver(this); 136 registrar_.Remove(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); 137 } 138} 139 140void ImmersiveModeControllerAsh::LayoutBrowserRootView() { 141 views::Widget* widget = browser_view_->frame(); 142 // Update the window caption buttons. 143 widget->non_client_view()->frame_view()->ResetWindowControls(); 144 widget->non_client_view()->frame_view()->InvalidateLayout(); 145 browser_view_->InvalidateLayout(); 146 widget->GetRootView()->Layout(); 147} 148 149bool ImmersiveModeControllerAsh::UpdateTabIndicators() { 150 bool has_tabstrip = browser_view_->IsBrowserTypeNormal(); 151 if (!IsEnabled() || !has_tabstrip) { 152 use_tab_indicators_ = false; 153 } else { 154 bool in_tab_fullscreen = browser_view_->browser()->fullscreen_controller()-> 155 IsWindowFullscreenForTabOrPending(); 156 use_tab_indicators_ = !in_tab_fullscreen; 157 } 158 159 bool show_tab_indicators = use_tab_indicators_ && !IsRevealed(); 160 if (show_tab_indicators != browser_view_->tabstrip()->IsImmersiveStyle()) { 161 browser_view_->tabstrip()->SetImmersiveStyle(show_tab_indicators); 162 return true; 163 } 164 return false; 165} 166 167void ImmersiveModeControllerAsh::OnImmersiveRevealStarted() { 168 visible_fraction_ = 0; 169 browser_view_->top_container()->SetPaintToLayer(true); 170 browser_view_->top_container()->SetFillsBoundsOpaquely(false); 171 UpdateTabIndicators(); 172 LayoutBrowserRootView(); 173 FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveRevealStarted()); 174} 175 176void ImmersiveModeControllerAsh::OnImmersiveRevealEnded() { 177 visible_fraction_ = 0; 178 browser_view_->top_container()->SetPaintToLayer(false); 179 UpdateTabIndicators(); 180 LayoutBrowserRootView(); 181} 182 183void ImmersiveModeControllerAsh::OnImmersiveFullscreenExited() { 184 browser_view_->top_container()->SetPaintToLayer(false); 185 UpdateTabIndicators(); 186 LayoutBrowserRootView(); 187} 188 189void ImmersiveModeControllerAsh::SetVisibleFraction(double visible_fraction) { 190 if (visible_fraction_ != visible_fraction) { 191 visible_fraction_ = visible_fraction; 192 browser_view_->Layout(); 193 } 194} 195 196std::vector<gfx::Rect> 197ImmersiveModeControllerAsh::GetVisibleBoundsInScreen() const { 198 views::View* top_container_view = browser_view_->top_container(); 199 gfx::Rect top_container_view_bounds = top_container_view->GetVisibleBounds(); 200 // TODO(tdanderson): Implement View::ConvertRectToScreen(). 201 gfx::Point top_container_view_bounds_in_screen_origin( 202 top_container_view_bounds.origin()); 203 views::View::ConvertPointToScreen(top_container_view, 204 &top_container_view_bounds_in_screen_origin); 205 gfx::Rect top_container_view_bounds_in_screen( 206 top_container_view_bounds_in_screen_origin, 207 top_container_view_bounds.size()); 208 209 std::vector<gfx::Rect> bounds_in_screen; 210 bounds_in_screen.push_back(top_container_view_bounds_in_screen); 211 bounds_in_screen.push_back(find_bar_visible_bounds_in_screen_); 212 return bounds_in_screen; 213} 214 215void ImmersiveModeControllerAsh::OnPostWindowStateTypeChange( 216 ash::wm::WindowState* window_state, 217 ash::wm::WindowStateType old_type) { 218 // Disable immersive fullscreen when the user exits fullscreen without going 219 // through FullscreenController::ToggleBrowserFullscreenMode(). This is the 220 // case if the user exits fullscreen via the restore button. 221 if (controller_->IsEnabled() && 222 !window_state->IsFullscreen() && 223 !window_state->IsMinimized()) { 224 browser_view_->FullscreenStateChanged(); 225 } 226} 227 228void ImmersiveModeControllerAsh::Observe( 229 int type, 230 const content::NotificationSource& source, 231 const content::NotificationDetails& details) { 232 DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type); 233 if (!controller_->IsEnabled()) 234 return; 235 236 bool tab_indicator_visibility_changed = UpdateTabIndicators(); 237 238 // Auto hide the shelf in immersive browser fullscreen. When auto hidden, the 239 // shelf displays a 3px 'light bar' when it is closed. When in immersive 240 // browser fullscreen and tab fullscreen, hide the shelf completely and 241 // prevent it from being revealed. 242 bool in_tab_fullscreen = content::Source<FullscreenController>(source)-> 243 IsWindowFullscreenForTabOrPending(); 244 ash::wm::GetWindowState(native_window_)->set_hide_shelf_when_fullscreen( 245 in_tab_fullscreen); 246 ash::Shell::GetInstance()->UpdateShelfVisibility(); 247 248 if (tab_indicator_visibility_changed) 249 LayoutBrowserRootView(); 250} 251