immersive_mode_controller_ash.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "content/public/browser/web_contents_view.h" 17#include "ui/aura/window.h" 18#include "ui/views/view.h" 19#include "ui/views/widget/widget.h" 20#include "ui/views/window/non_client_view.h" 21 22namespace { 23 24// Revealing the TopContainerView looks better if the animation starts and ends 25// just a few pixels before the view goes offscreen, which reduces the visual 26// "pop" as the 3-pixel tall "light bar" style tab strip becomes visible. 27const int kAnimationOffsetY = 3; 28 29// Converts from ImmersiveModeController::AnimateReveal to 30// ash::ImmersiveFullscreenController::AnimateReveal. 31ash::ImmersiveFullscreenController::AnimateReveal 32ToImmersiveFullscreenControllerAnimateReveal( 33 ImmersiveModeController::AnimateReveal animate_reveal) { 34 switch (animate_reveal) { 35 case ImmersiveModeController::ANIMATE_REVEAL_YES: 36 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_YES; 37 case ImmersiveModeController::ANIMATE_REVEAL_NO: 38 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; 39 } 40 NOTREACHED(); 41 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; 42} 43 44} // namespace 45 46ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() 47 : controller_(new ash::ImmersiveFullscreenController), 48 browser_view_(NULL), 49 native_window_(NULL), 50 observers_enabled_(false), 51 use_tab_indicators_(false), 52 visible_fraction_(1) { 53} 54 55ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { 56 EnableWindowObservers(false); 57} 58 59void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { 60 browser_view_ = browser_view; 61 native_window_ = browser_view_->GetNativeWindow(); 62 controller_->Init(this, browser_view_->frame(), 63 browser_view_->top_container()); 64} 65 66void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { 67 if (controller_->IsEnabled() == enabled) 68 return; 69 70 EnableWindowObservers(enabled); 71 72 controller_->SetEnabled(browser_view_->browser()->is_app() ? 73 ash::ImmersiveFullscreenController::WINDOW_TYPE_HOSTED_APP : 74 ash::ImmersiveFullscreenController::WINDOW_TYPE_BROWSER 75 , enabled); 76} 77 78bool ImmersiveModeControllerAsh::IsEnabled() const { 79 return controller_->IsEnabled(); 80} 81 82bool ImmersiveModeControllerAsh::ShouldHideTabIndicators() const { 83 return !use_tab_indicators_; 84} 85 86bool ImmersiveModeControllerAsh::ShouldHideTopViews() const { 87 return controller_->IsEnabled() && !controller_->IsRevealed(); 88} 89 90bool ImmersiveModeControllerAsh::IsRevealed() const { 91 return controller_->IsRevealed(); 92} 93 94int ImmersiveModeControllerAsh::GetTopContainerVerticalOffset( 95 const gfx::Size& top_container_size) const { 96 if (!IsEnabled()) 97 return 0; 98 99 // The TopContainerView is flush with the top of |browser_view_| when the 100 // top-of-window views are fully closed so that when the tab indicators are 101 // used, the "light bar" style tab strip is flush with the top of 102 // |browser_view_|. 103 if (!IsRevealed()) 104 return 0; 105 106 int height = top_container_size.height() - kAnimationOffsetY; 107 return static_cast<int>(height * (visible_fraction_ - 1)); 108} 109 110ImmersiveRevealedLock* ImmersiveModeControllerAsh::GetRevealedLock( 111 AnimateReveal animate_reveal) { 112 return controller_->GetRevealedLock( 113 ToImmersiveFullscreenControllerAnimateReveal(animate_reveal)); 114} 115 116void ImmersiveModeControllerAsh::OnFindBarVisibleBoundsChanged( 117 const gfx::Rect& new_visible_bounds_in_screen) { 118 find_bar_visible_bounds_in_screen_ = new_visible_bounds_in_screen; 119} 120 121void ImmersiveModeControllerAsh::SetupForTest() { 122 controller_->SetupForTest(); 123} 124 125void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { 126 if (observers_enabled_ == enable) 127 return; 128 observers_enabled_ = enable; 129 130 content::Source<FullscreenController> source( 131 browser_view_->browser()->fullscreen_controller()); 132 if (enable) { 133 ash::wm::GetWindowState(native_window_)->AddObserver(this); 134 registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); 135 } else { 136 ash::wm::GetWindowState(native_window_)->RemoveObserver(this); 137 registrar_.Remove(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); 138 } 139} 140 141void ImmersiveModeControllerAsh::LayoutBrowserRootView() { 142 views::Widget* widget = browser_view_->frame(); 143 // Update the window caption buttons. 144 widget->non_client_view()->frame_view()->ResetWindowControls(); 145 widget->non_client_view()->frame_view()->InvalidateLayout(); 146 browser_view_->InvalidateLayout(); 147 widget->GetRootView()->Layout(); 148} 149 150bool ImmersiveModeControllerAsh::UpdateTabIndicators() { 151 bool has_tabstrip = browser_view_->IsBrowserTypeNormal(); 152 if (!IsEnabled() || !has_tabstrip) { 153 use_tab_indicators_ = false; 154 } else { 155 bool in_tab_fullscreen = browser_view_->browser()->fullscreen_controller()-> 156 IsFullscreenForTabOrPending(); 157 use_tab_indicators_ = !in_tab_fullscreen; 158 } 159 160 bool show_tab_indicators = use_tab_indicators_ && !IsRevealed(); 161 if (show_tab_indicators != browser_view_->tabstrip()->IsImmersiveStyle()) { 162 browser_view_->tabstrip()->SetImmersiveStyle(show_tab_indicators); 163 return true; 164 } 165 return false; 166} 167 168void ImmersiveModeControllerAsh::OnImmersiveRevealStarted() { 169 visible_fraction_ = 0; 170 browser_view_->top_container()->SetPaintToLayer(true); 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::OnPostWindowShowTypeChange( 216 ash::wm::WindowState* window_state, 217 ash::wm::WindowShowType old_type) { 218 // Disable immersive fullscreen when the user exits fullscreen without going 219 // through FullscreenController::ToggleFullscreenMode(). This is the case if 220 // 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 IsFullscreenForTabOrPending(); 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