immersive_mode_controller_ash.cc revision f2477e01787aa58f445919b809d89e252beef54f
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// The height of the region in pixels at the top edge of the screen in which to 30// steal touch events targetted at the web contents while in immersive 31// fullscreen. This region is used to allow us to get edge gestures even if the 32// web contents consumes all touch events. 33const int kStealTouchEventsFromWebContentsRegionHeightPx = 8; 34 35// Converts from ImmersiveModeController::AnimateReveal to 36// ash::ImmersiveFullscreenController::AnimateReveal. 37ash::ImmersiveFullscreenController::AnimateReveal 38ToImmersiveFullscreenControllerAnimateReveal( 39 ImmersiveModeController::AnimateReveal animate_reveal) { 40 switch (animate_reveal) { 41 case ImmersiveModeController::ANIMATE_REVEAL_YES: 42 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_YES; 43 case ImmersiveModeController::ANIMATE_REVEAL_NO: 44 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; 45 } 46 NOTREACHED(); 47 return ash::ImmersiveFullscreenController::ANIMATE_REVEAL_NO; 48} 49 50} // namespace 51 52ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() 53 : controller_(new ash::ImmersiveFullscreenController), 54 browser_view_(NULL), 55 native_window_(NULL), 56 observers_enabled_(false), 57 use_tab_indicators_(false), 58 visible_fraction_(1) { 59} 60 61ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { 62 EnableWindowObservers(false); 63} 64 65void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { 66 browser_view_ = browser_view; 67 native_window_ = browser_view_->GetNativeWindow(); 68 controller_->Init(this, browser_view_->frame(), 69 browser_view_->top_container()); 70} 71 72void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { 73 if (controller_->IsEnabled() == enabled) 74 return; 75 76 EnableWindowObservers(enabled); 77 78 // Use a short "light bar" version of the tab strip when the top-of-window 79 // views are closed. If the user additionally enters into tab fullscreen, 80 // the tab indicators will be hidden. 81 use_tab_indicators_ = enabled; 82 83 controller_->SetEnabled(enabled); 84} 85 86bool ImmersiveModeControllerAsh::IsEnabled() const { 87 return controller_->IsEnabled(); 88} 89 90bool ImmersiveModeControllerAsh::ShouldHideTabIndicators() const { 91 return !use_tab_indicators_; 92} 93 94bool ImmersiveModeControllerAsh::ShouldHideTopViews() const { 95 return controller_->IsEnabled() && !controller_->IsRevealed(); 96} 97 98bool ImmersiveModeControllerAsh::IsRevealed() const { 99 return controller_->IsRevealed(); 100} 101 102int ImmersiveModeControllerAsh::GetTopContainerVerticalOffset( 103 const gfx::Size& top_container_size) const { 104 if (!IsEnabled()) 105 return 0; 106 107 // The TopContainerView is flush with the top of |browser_view_| when the 108 // top-of-window views are fully closed so that when the tab indicators are 109 // used, the "light bar" style tab strip is flush with the top of 110 // |browser_view_|. 111 if (!IsRevealed()) 112 return 0; 113 114 int height = top_container_size.height() - kAnimationOffsetY; 115 return static_cast<int>(height * (visible_fraction_ - 1)); 116} 117 118ImmersiveRevealedLock* ImmersiveModeControllerAsh::GetRevealedLock( 119 AnimateReveal animate_reveal) { 120 return controller_->GetRevealedLock( 121 ToImmersiveFullscreenControllerAnimateReveal(animate_reveal)); 122} 123 124void ImmersiveModeControllerAsh::OnFindBarVisibleBoundsChanged( 125 const gfx::Rect& new_visible_bounds_in_screen) { 126 find_bar_visible_bounds_in_screen_ = new_visible_bounds_in_screen; 127} 128 129void ImmersiveModeControllerAsh::SetupForTest() { 130 controller_->SetupForTest(); 131} 132 133void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { 134 if (observers_enabled_ == enable) 135 return; 136 observers_enabled_ = enable; 137 138 content::Source<FullscreenController> source( 139 browser_view_->browser()->fullscreen_controller()); 140 if (enable) { 141 ash::wm::GetWindowState(native_window_)->AddObserver(this); 142 registrar_.Add(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); 143 } else { 144 ash::wm::GetWindowState(native_window_)->RemoveObserver(this); 145 registrar_.Remove(this, chrome::NOTIFICATION_FULLSCREEN_CHANGED, source); 146 } 147} 148 149void ImmersiveModeControllerAsh::LayoutBrowserRootView() { 150 views::Widget* widget = browser_view_->frame(); 151 // Update the window caption buttons. 152 widget->non_client_view()->frame_view()->ResetWindowControls(); 153 // Layout all views, including BrowserView. 154 widget->GetRootView()->Layout(); 155} 156 157void ImmersiveModeControllerAsh::SetRenderWindowTopInsetsForTouch( 158 int top_inset) { 159 content::WebContents* contents = browser_view_->GetActiveWebContents(); 160 if (contents) { 161 aura::Window* window = contents->GetView()->GetContentNativeView(); 162 // |window| is NULL if the renderer crashed. 163 if (window) { 164 gfx::Insets inset(top_inset, 0, 0, 0); 165 window->SetHitTestBoundsOverrideOuter( 166 window->hit_test_bounds_override_outer_mouse(), 167 inset); 168 } 169 } 170} 171 172void ImmersiveModeControllerAsh::SetTabIndicatorsVisible(bool visible) { 173 DCHECK(!visible || use_tab_indicators_); 174 if (browser_view_->tabstrip()) 175 browser_view_->tabstrip()->SetImmersiveStyle(visible); 176} 177 178void ImmersiveModeControllerAsh::OnImmersiveRevealStarted() { 179 visible_fraction_ = 0; 180 browser_view_->top_container()->SetPaintToLayer(true); 181 SetTabIndicatorsVisible(false); 182 SetRenderWindowTopInsetsForTouch(0); 183 LayoutBrowserRootView(); 184 FOR_EACH_OBSERVER(Observer, observers_, OnImmersiveRevealStarted()); 185} 186 187void ImmersiveModeControllerAsh::OnImmersiveRevealEnded() { 188 visible_fraction_ = 0; 189 browser_view_->top_container()->SetPaintToLayer(false); 190 SetTabIndicatorsVisible(use_tab_indicators_); 191 SetRenderWindowTopInsetsForTouch( 192 kStealTouchEventsFromWebContentsRegionHeightPx); 193 LayoutBrowserRootView(); 194} 195 196void ImmersiveModeControllerAsh::OnImmersiveFullscreenExited() { 197 browser_view_->top_container()->SetPaintToLayer(false); 198 SetTabIndicatorsVisible(false); 199 SetRenderWindowTopInsetsForTouch(0); 200 LayoutBrowserRootView(); 201} 202 203void ImmersiveModeControllerAsh::SetVisibleFraction(double visible_fraction) { 204 if (visible_fraction_ != visible_fraction) { 205 visible_fraction_ = visible_fraction; 206 browser_view_->Layout(); 207 } 208} 209 210std::vector<gfx::Rect> 211ImmersiveModeControllerAsh::GetVisibleBoundsInScreen() const { 212 views::View* top_container_view = browser_view_->top_container(); 213 gfx::Rect top_container_view_bounds = top_container_view->GetVisibleBounds(); 214 // TODO(tdanderson): Implement View::ConvertRectToScreen(). 215 gfx::Point top_container_view_bounds_in_screen_origin( 216 top_container_view_bounds.origin()); 217 views::View::ConvertPointToScreen(top_container_view, 218 &top_container_view_bounds_in_screen_origin); 219 gfx::Rect top_container_view_bounds_in_screen( 220 top_container_view_bounds_in_screen_origin, 221 top_container_view_bounds.size()); 222 223 std::vector<gfx::Rect> bounds_in_screen; 224 bounds_in_screen.push_back(top_container_view_bounds_in_screen); 225 bounds_in_screen.push_back(find_bar_visible_bounds_in_screen_); 226 return bounds_in_screen; 227} 228 229void ImmersiveModeControllerAsh::OnWindowShowTypeChanged( 230 ash::wm::WindowState* window_state, 231 ash::wm::WindowShowType old_type) { 232 // Disable immersive fullscreen when the user exits fullscreen without going 233 // through FullscreenController::ToggleFullscreenMode(). This is the case if 234 // the user exits fullscreen via the restore button. 235 if (controller_->IsEnabled() && 236 !window_state->IsFullscreen() && 237 !window_state->IsMinimized()) { 238 browser_view_->FullscreenStateChanged(); 239 } 240} 241 242void ImmersiveModeControllerAsh::Observe( 243 int type, 244 const content::NotificationSource& source, 245 const content::NotificationDetails& details) { 246 DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type); 247 if (!controller_->IsEnabled()) 248 return; 249 250 bool in_tab_fullscreen = content::Source<FullscreenController>(source)-> 251 IsFullscreenForTabOrPending(); 252 253 bool used_tab_indicators = use_tab_indicators_; 254 use_tab_indicators_ = !in_tab_fullscreen; 255 SetTabIndicatorsVisible(use_tab_indicators_ && !controller_->IsRevealed()); 256 257 // Auto hide the shelf in immersive browser fullscreen. When auto hidden, the 258 // shelf displays a 3px 'light bar' when it is closed. When in immersive 259 // browser fullscreen and tab fullscreen, hide the shelf completely and 260 // prevent it from being revealed. 261 ash::wm::GetWindowState(native_window_)->set_hide_shelf_when_fullscreen( 262 in_tab_fullscreen); 263 ash::Shell::GetInstance()->UpdateShelfVisibility(); 264 265 if (use_tab_indicators_ != used_tab_indicators) 266 LayoutBrowserRootView(); 267} 268