Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" | 5 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" |
| 6 | 6 |
| 7 #include "ash/ash_switches.h" | 7 #include "ash/ash_switches.h" |
| 8 #include "ash/shell.h" | 8 #include "ash/shell.h" |
| 9 #include "ash/wm/window_properties.h" | 9 #include "ash/wm/window_properties.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "chrome/browser/ui/browser_commands.h" | |
|
James Cook
2013/04/11 23:35:58
nit: Do you need this?
| |
| 11 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" | 12 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" |
| 12 #include "chrome/browser/ui/views/frame/browser_view.h" | 13 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 13 #include "chrome/browser/ui/views/frame/top_container_view.h" | 14 #include "chrome/browser/ui/views/frame/top_container_view.h" |
| 14 #include "chrome/browser/ui/views/tabs/tab_strip.h" | 15 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
| 15 #include "ui/aura/client/activation_client.h" | 16 #include "ui/aura/client/activation_client.h" |
| 16 #include "ui/aura/client/aura_constants.h" | 17 #include "ui/aura/client/aura_constants.h" |
| 17 #include "ui/aura/client/capture_client.h" | 18 #include "ui/aura/client/capture_client.h" |
| 18 #include "ui/aura/env.h" | 19 #include "ui/aura/env.h" |
| 19 #include "ui/aura/window.h" | 20 #include "ui/aura/window.h" |
| 20 #include "ui/aura/window_observer.h" | 21 #include "ui/aura/window_observer.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 38 // few pixels before the view goes completely off the screen, which reduces | 39 // few pixels before the view goes completely off the screen, which reduces |
| 39 // the visual "pop" as the 2-pixel tall immersive-style tabs become visible. | 40 // the visual "pop" as the 2-pixel tall immersive-style tabs become visible. |
| 40 const int kAnimationOffsetY = 3; | 41 const int kAnimationOffsetY = 3; |
| 41 | 42 |
| 42 // Duration for the reveal show/hide slide animation. The slower duration is | 43 // Duration for the reveal show/hide slide animation. The slower duration is |
| 43 // used for the initial slide out to give the user more change to see what | 44 // used for the initial slide out to give the user more change to see what |
| 44 // happened. | 45 // happened. |
| 45 const int kRevealSlowAnimationDurationMs = 400; | 46 const int kRevealSlowAnimationDurationMs = 400; |
| 46 const int kRevealFastAnimationDurationMs = 200; | 47 const int kRevealFastAnimationDurationMs = 200; |
| 47 | 48 |
| 49 // If |hovered| is true, moves the mouse above |view|. Moves it outside of | |
| 50 // |view| otherwise. | |
| 51 // Should not be called outside of tests. | |
| 52 void MoveMouse(views::View* view, bool hovered) { | |
| 53 gfx::Point cursor_pos; | |
| 54 if (!hovered) { | |
| 55 int bottom_edge = view->bounds().bottom(); | |
| 56 cursor_pos = gfx::Point(0, bottom_edge + 100); | |
| 57 } | |
| 58 views::View::ConvertPointToScreen(view, &cursor_pos); | |
| 59 aura::Env::GetInstance()->set_last_mouse_location(cursor_pos); | |
| 60 } | |
| 61 | |
| 48 // Returns true if the currently active window is a transient child of | 62 // Returns true if the currently active window is a transient child of |
| 49 // |toplevel|. | 63 // |toplevel|. |
| 50 bool IsActiveWindowTransientChildOf(gfx::NativeWindow toplevel) { | 64 bool IsActiveWindowTransientChildOf(aura::Window* toplevel) { |
| 51 aura::Window* active_window = aura::client::GetActivationClient( | 65 aura::Window* active_window = aura::client::GetActivationClient( |
| 52 toplevel->GetRootWindow())->GetActiveWindow(); | 66 toplevel->GetRootWindow())->GetActiveWindow(); |
| 53 | 67 |
| 54 if (!toplevel || !active_window) | 68 if (!toplevel || !active_window) |
| 55 return false; | 69 return false; |
| 56 | 70 |
| 57 for (aura::Window* window = active_window; window; | 71 for (aura::Window* window = active_window; window; |
| 58 window = window->transient_parent()) { | 72 window = window->transient_parent()) { |
| 59 if (window == toplevel) | 73 if (window == toplevel) |
| 60 return true; | 74 return true; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 77 if (controller_) | 91 if (controller_) |
| 78 controller_->UnlockRevealedState(); | 92 controller_->UnlockRevealedState(); |
| 79 } | 93 } |
| 80 | 94 |
| 81 private: | 95 private: |
| 82 base::WeakPtr<ImmersiveModeControllerAsh> controller_; | 96 base::WeakPtr<ImmersiveModeControllerAsh> controller_; |
| 83 | 97 |
| 84 DISALLOW_COPY_AND_ASSIGN(RevealedLockAsh); | 98 DISALLOW_COPY_AND_ASSIGN(RevealedLockAsh); |
| 85 }; | 99 }; |
| 86 | 100 |
| 101 //////////////////////////////////////////////////////////////////////////////// | |
| 102 | |
| 103 // Manages widgets which should move in sync with the top-of-window views. | |
| 104 class AnchoredWidgetManager : public views::WidgetObserver { | |
| 105 public: | |
| 106 AnchoredWidgetManager(ImmersiveModeControllerAsh* controller, | |
| 107 BrowserView* browser_view); | |
| 108 virtual ~AnchoredWidgetManager(); | |
| 109 | |
| 110 // Anchors |widget| such that it stays |y_offset| below the top-of-window | |
| 111 // views. |widget| will be repositioned whenever the top-of-window views are | |
| 112 // animated (top-of-window views revealing / unrevealing) or the top-of-window | |
| 113 // bounds change (eg the bookmark bar is shown). | |
| 114 // If the top-of-window views are revealed (or become revealed), |widget| will | |
| 115 // keep the top-of-window views revealed till |widget| is hidden or | |
| 116 // RemoveAnchoredWidget() is called. | |
| 117 void AddAnchoredWidget(views::Widget* widget, int y_offset); | |
| 118 | |
| 119 // Stops managing |widget|'s y position. | |
| 120 // Closes the top-of-window views if no locks or other anchored widgets are | |
| 121 // keeping the top-of-window views revealed. | |
| 122 void RemoveAnchoredWidget(views::Widget* widget); | |
| 123 | |
| 124 // Adjusts the y positions of the anchored widgets for the new top container | |
| 125 // bounds. | |
| 126 void OnTopContainerBoundsChanged(); | |
| 127 | |
| 128 const std::set<views::Widget*>& visible_anchored_widgets() const { | |
| 129 return visible_; | |
| 130 } | |
| 131 | |
| 132 private: | |
| 133 // Updates |revealed_lock_| based on the visible anchored widgets. | |
| 134 void UpdateRevealedLock(); | |
| 135 | |
| 136 // Updates the y position of |widget| given |y_offset| and the top | |
| 137 // container's target bounds. | |
| 138 void UpdateWidgetBounds(views::Widget* widget, int y_offset); | |
| 139 | |
| 140 // views::WidgetObserver overrides: | |
| 141 virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE; | |
| 142 virtual void OnWidgetVisibilityChanged(views::Widget* widget, | |
| 143 bool visible) OVERRIDE; | |
| 144 | |
| 145 ImmersiveModeControllerAsh* controller_; | |
| 146 | |
| 147 BrowserView* browser_view_; | |
| 148 | |
| 149 // Mapping of anchored widgets to the y offset below the top-of-window views | |
| 150 // that they should be positioned at. | |
| 151 std::map<views::Widget*, int> widgets_; | |
| 152 | |
| 153 // The subset of |widgets_| which are visible. | |
| 154 std::set<views::Widget*> visible_; | |
| 155 | |
| 156 // Lock which keeps the top-of-window views revealed based on the visible | |
| 157 // anchored widgets. | |
| 158 scoped_ptr<ImmersiveModeController::RevealedLock> revealed_lock_; | |
| 159 | |
| 160 DISALLOW_COPY_AND_ASSIGN(AnchoredWidgetManager); | |
| 161 }; | |
| 162 | |
| 163 AnchoredWidgetManager::AnchoredWidgetManager( | |
| 164 ImmersiveModeControllerAsh* controller, | |
| 165 BrowserView* browser_view) | |
| 166 : controller_(controller), | |
| 167 browser_view_(browser_view) { | |
| 168 } | |
| 169 | |
| 170 AnchoredWidgetManager::~AnchoredWidgetManager() { | |
| 171 for (std::map<views::Widget*, int>::iterator it = widgets_.begin(); | |
| 172 it != widgets_.end(); ++it) { | |
| 173 RemoveAnchoredWidget(it->first); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 void AnchoredWidgetManager::AddAnchoredWidget(views::Widget* widget, | |
| 178 int y_offset) { | |
| 179 DCHECK(widget); | |
| 180 bool already_added = widgets_.count(widget); | |
| 181 widgets_[widget] = y_offset; | |
| 182 | |
| 183 if (already_added) | |
| 184 return; | |
| 185 | |
| 186 widget->AddObserver(this); | |
| 187 | |
| 188 if (widget->IsVisible()) | |
| 189 visible_.insert(widget); | |
| 190 | |
| 191 UpdateRevealedLock(); | |
| 192 UpdateWidgetBounds(widget, y_offset); | |
| 193 } | |
| 194 | |
| 195 void AnchoredWidgetManager::RemoveAnchoredWidget(views::Widget* widget) { | |
| 196 if (!widgets_.count(widget)) | |
| 197 return; | |
| 198 | |
| 199 widget->RemoveObserver(this); | |
| 200 widgets_.erase(widget); | |
| 201 visible_.erase(widget); | |
| 202 | |
| 203 UpdateRevealedLock(); | |
| 204 } | |
| 205 | |
| 206 void AnchoredWidgetManager::OnTopContainerBoundsChanged() { | |
| 207 for (std::map<views::Widget*, int>::iterator it = widgets_.begin(); | |
| 208 it != widgets_.end(); ++it) { | |
| 209 UpdateWidgetBounds(it->first, it->second); | |
| 210 } | |
| 211 | |
| 212 UpdateRevealedLock(); | |
| 213 } | |
| 214 | |
| 215 void AnchoredWidgetManager::UpdateRevealedLock() { | |
| 216 if (visible_.empty()) { | |
| 217 revealed_lock_.reset(); | |
| 218 } else if (controller_->IsRevealed()) { | |
| 219 // It is hard to determine the required initial transforms and the required | |
| 220 // durations of the animations of |visible_| such that they appear to be | |
| 221 // anchored to the top-of-window views while the top-of-window views are | |
| 222 // animating. Skip to the end of the reveal animation instead. | |
| 223 // We do not query the controller's reveal state because we may be called | |
| 224 // as a result of LayoutBrowserView() in MaybeStartReveal() when | |
| 225 // |reveal_state_| is SLIDING_OPEN but no animation is running yet. | |
| 226 ui::Layer* top_container_layer = browser_view_->top_container()->layer(); | |
| 227 if (top_container_layer && | |
| 228 top_container_layer->GetAnimator()->is_animating()) { | |
| 229 controller_->MaybeRevealWithoutAnimation(); | |
| 230 } | |
| 231 | |
| 232 if (!revealed_lock_.get()) | |
| 233 revealed_lock_.reset(controller_->GetRevealedLock()); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 void AnchoredWidgetManager::UpdateWidgetBounds(views::Widget* widget, | |
| 238 int y_offset) { | |
| 239 if (!widget->IsVisible()) | |
| 240 return; | |
| 241 | |
| 242 gfx::Rect top_container_target_bounds = | |
| 243 browser_view_->top_container()->GetTargetBoundsInScreen(); | |
| 244 gfx::Rect bounds(widget->GetWindowBoundsInScreen()); | |
| 245 bounds.set_y( | |
| 246 top_container_target_bounds.bottom() + y_offset); | |
| 247 widget->SetBounds(bounds); | |
| 248 } | |
| 249 | |
| 250 void AnchoredWidgetManager::OnWidgetDestroying(views::Widget* widget) { | |
| 251 RemoveAnchoredWidget(widget); | |
| 252 } | |
| 253 | |
| 254 void AnchoredWidgetManager::OnWidgetVisibilityChanged(views::Widget* widget, | |
| 255 bool visible) { | |
| 256 if (visible) | |
| 257 visible_.insert(widget); | |
| 258 else | |
| 259 visible_.erase(widget); | |
| 260 | |
| 261 UpdateRevealedLock(); | |
| 262 | |
| 263 std::map<views::Widget*, int>::iterator it = widgets_.find(widget); | |
| 264 DCHECK(it != widgets_.end()); | |
| 265 UpdateWidgetBounds(it->first, it->second); | |
| 266 } | |
| 267 | |
| 87 } // namespace | 268 } // namespace |
| 88 | 269 |
| 89 //////////////////////////////////////////////////////////////////////////////// | 270 //////////////////////////////////////////////////////////////////////////////// |
| 90 | 271 |
| 91 // Observer to watch for window restore. views::Widget does not provide a hook | 272 // Observer to watch for window restore. views::Widget does not provide a hook |
| 92 // to observe for window restore, so do this at the Aura level. | 273 // to observe for window restore, so do this at the Aura level. |
| 93 class ImmersiveModeControllerAsh::WindowObserver : public aura::WindowObserver { | 274 class ImmersiveModeControllerAsh::WindowObserver : public aura::WindowObserver { |
| 94 public: | 275 public: |
| 95 explicit WindowObserver(ImmersiveModeControllerAsh* controller) | 276 explicit WindowObserver(ImmersiveModeControllerAsh* controller) |
| 96 : controller_(controller) { | 277 : controller_(controller) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 126 } | 307 } |
| 127 | 308 |
| 128 private: | 309 private: |
| 129 ImmersiveModeControllerAsh* controller_; // Not owned. | 310 ImmersiveModeControllerAsh* controller_; // Not owned. |
| 130 | 311 |
| 131 DISALLOW_COPY_AND_ASSIGN(WindowObserver); | 312 DISALLOW_COPY_AND_ASSIGN(WindowObserver); |
| 132 }; | 313 }; |
| 133 | 314 |
| 134 //////////////////////////////////////////////////////////////////////////////// | 315 //////////////////////////////////////////////////////////////////////////////// |
| 135 | 316 |
| 136 class ImmersiveModeControllerAsh::AnimationObserver | |
| 137 : public ui::ImplicitAnimationObserver { | |
| 138 public: | |
| 139 enum AnimationType { | |
| 140 SLIDE_OPEN, | |
| 141 SLIDE_CLOSED, | |
| 142 }; | |
| 143 | |
| 144 AnimationObserver(ImmersiveModeControllerAsh* controller, AnimationType type) | |
| 145 : controller_(controller), animation_type_(type) {} | |
| 146 virtual ~AnimationObserver() {} | |
| 147 | |
| 148 // ui::ImplicitAnimationObserver overrides: | |
| 149 virtual void OnImplicitAnimationsCompleted() OVERRIDE { | |
| 150 if (animation_type_ == SLIDE_OPEN) | |
| 151 controller_->OnSlideOpenAnimationCompleted(); | |
| 152 else if (animation_type_ == SLIDE_CLOSED) | |
| 153 controller_->OnSlideClosedAnimationCompleted(); | |
| 154 else | |
| 155 NOTREACHED(); | |
| 156 } | |
| 157 | |
| 158 private: | |
| 159 ImmersiveModeControllerAsh* controller_; | |
| 160 AnimationType animation_type_; | |
| 161 | |
| 162 DISALLOW_COPY_AND_ASSIGN(AnimationObserver); | |
| 163 }; | |
| 164 | |
| 165 //////////////////////////////////////////////////////////////////////////////// | |
| 166 | |
| 167 ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() | 317 ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() |
| 168 : browser_view_(NULL), | 318 : browser_view_(NULL), |
| 169 enabled_(false), | 319 enabled_(false), |
| 170 reveal_state_(CLOSED), | 320 reveal_state_(CLOSED), |
| 171 revealed_lock_count_(0), | 321 revealed_lock_count_(0), |
| 172 hide_tab_indicators_(false), | 322 hide_tab_indicators_(false), |
| 173 native_window_(NULL), | 323 native_window_(NULL), |
| 174 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 324 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 175 } | 325 } |
| 176 | 326 |
| 177 ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { | 327 ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() { |
| 178 // The browser view is being destroyed so there's no need to update its | 328 // The browser view is being destroyed so there's no need to update its |
| 179 // layout or layers, even if the top views are revealed. But the window | 329 // layout or layers, even if the top views are revealed. But the window |
| 180 // observers still need to be removed. | 330 // observers still need to be removed. |
| 181 EnableWindowObservers(false); | 331 EnableWindowObservers(false); |
| 182 } | 332 } |
| 183 | 333 |
| 184 void ImmersiveModeControllerAsh::LockRevealedState() { | 334 void ImmersiveModeControllerAsh::LockRevealedState() { |
| 185 ++revealed_lock_count_; | 335 ++revealed_lock_count_; |
| 186 if (revealed_lock_count_ == 1) | 336 if (revealed_lock_count_ == 1) |
| 187 MaybeStartReveal(); | 337 MaybeStartReveal(ANIMATE_FAST); |
| 188 } | 338 } |
| 189 | 339 |
| 190 void ImmersiveModeControllerAsh::UnlockRevealedState() { | 340 void ImmersiveModeControllerAsh::UnlockRevealedState() { |
| 191 --revealed_lock_count_; | 341 --revealed_lock_count_; |
| 192 DCHECK_GE(revealed_lock_count_, 0); | 342 DCHECK_GE(revealed_lock_count_, 0); |
| 193 if (revealed_lock_count_ == 0) | 343 if (revealed_lock_count_ == 0) |
| 194 MaybeEndReveal(ANIMATE_FAST); | 344 MaybeEndReveal(ANIMATE_FAST); |
| 195 } | 345 } |
| 196 | 346 |
| 347 void ImmersiveModeControllerAsh::MaybeRevealWithoutAnimation() { | |
| 348 MaybeStartReveal(ANIMATE_NO); | |
| 349 } | |
| 350 | |
| 197 void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { | 351 void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) { |
| 198 browser_view_ = browser_view; | 352 browser_view_ = browser_view; |
| 199 // Browser view is detached from its widget during destruction. Cache the | 353 // Browser view is detached from its widget during destruction. Cache the |
| 200 // window pointer so |this| can stop observing during destruction. | 354 // window pointer so |this| can stop observing during destruction. |
| 201 native_window_ = browser_view_->GetNativeWindow(); | 355 native_window_ = browser_view_->GetNativeWindow(); |
| 202 DCHECK(native_window_); | 356 DCHECK(native_window_); |
| 203 EnableWindowObservers(true); | 357 EnableWindowObservers(true); |
| 204 | 358 |
| 205 slide_open_observer_.reset( | |
| 206 new AnimationObserver(this, AnimationObserver::SLIDE_OPEN)); | |
| 207 slide_closed_observer_.reset( | |
| 208 new AnimationObserver(this, AnimationObserver::SLIDE_CLOSED)); | |
| 209 | |
| 210 // Optionally allow the tab indicators to be hidden. | 359 // Optionally allow the tab indicators to be hidden. |
| 211 hide_tab_indicators_ = CommandLine::ForCurrentProcess()-> | 360 hide_tab_indicators_ = CommandLine::ForCurrentProcess()-> |
| 212 HasSwitch(ash::switches::kAshImmersiveHideTabIndicators); | 361 HasSwitch(ash::switches::kAshImmersiveHideTabIndicators); |
| 362 | |
| 363 anchored_widget_manager_.reset( | |
| 364 new AnchoredWidgetManager(this, browser_view_)); | |
| 213 } | 365 } |
| 214 | 366 |
| 215 void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { | 367 void ImmersiveModeControllerAsh::SetEnabled(bool enabled) { |
| 216 DCHECK(browser_view_) << "Must initialize before enabling"; | 368 DCHECK(browser_view_) << "Must initialize before enabling"; |
| 217 if (enabled_ == enabled) | 369 if (enabled_ == enabled) |
| 218 return; | 370 return; |
| 219 enabled_ = enabled; | 371 enabled_ = enabled; |
| 220 | 372 |
| 221 if (enabled_) { | 373 if (enabled_) { |
| 222 // Animate enabling immersive mode by sliding out the top-of-window views. | 374 // Animate enabling immersive mode by sliding out the top-of-window views. |
| 223 // No animation occurs if a lock is holding the top-of-window views open. | 375 // No animation occurs if a lock is holding the top-of-window views open. |
| 224 | 376 |
| 225 // Do a reveal to set the initial state for the animation. (And any | 377 // Do a reveal to set the initial state for the animation. (And any |
| 226 // required state in case the animation cannot run because of a lock holding | 378 // required state in case the animation cannot run because of a lock holding |
| 227 // the top-of-window views open.) | 379 // the top-of-window views open.) |
| 228 StartReveal(ANIMATE_NO); | 380 MaybeStartReveal(ANIMATE_NO); |
| 229 | 381 |
| 230 // Reset the mouse and the focus revealed locks so that they do not affect | 382 // Reset the mouse and the focus revealed locks so that they do not affect |
| 231 // whether the top-of-window views are hidden. Reacquire the locks if ending | 383 // whether the top-of-window views are hidden. Reacquire the locks if ending |
| 232 // the reveal is unsuccessful. | 384 // the reveal is unsuccessful. |
| 233 bool had_mouse_revealed_lock = (mouse_revealed_lock_.get() != NULL); | 385 bool had_mouse_revealed_lock = (mouse_revealed_lock_.get() != NULL); |
| 234 bool had_focus_revealed_lock = (focus_revealed_lock_.get() != NULL); | 386 bool had_focus_revealed_lock = (focus_revealed_lock_.get() != NULL); |
| 235 mouse_revealed_lock_.reset(); | 387 mouse_revealed_lock_.reset(); |
| 236 focus_revealed_lock_.reset(); | 388 focus_revealed_lock_.reset(); |
| 237 | 389 |
| 238 // Try doing the animation. | 390 // Try doing the animation. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 if (reveal_layer) | 440 if (reveal_layer) |
| 289 reveal_layer->parent()->StackAtTop(reveal_layer); | 441 reveal_layer->parent()->StackAtTop(reveal_layer); |
| 290 } | 442 } |
| 291 } | 443 } |
| 292 | 444 |
| 293 ImmersiveModeControllerAsh::RevealedLock* | 445 ImmersiveModeControllerAsh::RevealedLock* |
| 294 ImmersiveModeControllerAsh::GetRevealedLock() { | 446 ImmersiveModeControllerAsh::GetRevealedLock() { |
| 295 return new RevealedLockAsh(weak_ptr_factory_.GetWeakPtr()); | 447 return new RevealedLockAsh(weak_ptr_factory_.GetWeakPtr()); |
| 296 } | 448 } |
| 297 | 449 |
| 450 void ImmersiveModeControllerAsh::AnchorWidgetToTopContainer( | |
| 451 views::Widget* widget, | |
| 452 int y_offset) { | |
| 453 anchored_widget_manager_->AddAnchoredWidget(widget, y_offset); | |
| 454 } | |
| 455 | |
| 456 void ImmersiveModeControllerAsh::UnanchorWidgetFromTopContainer( | |
| 457 views::Widget* widget) { | |
| 458 anchored_widget_manager_->RemoveAnchoredWidget(widget); | |
| 459 } | |
| 460 | |
| 461 void ImmersiveModeControllerAsh::OnTopContainerBoundsChanged() { | |
| 462 anchored_widget_manager_->OnTopContainerBoundsChanged(); | |
| 463 } | |
| 464 | |
| 298 //////////////////////////////////////////////////////////////////////////////// | 465 //////////////////////////////////////////////////////////////////////////////// |
| 299 // Observers: | 466 // Observers: |
| 300 | 467 |
| 301 void ImmersiveModeControllerAsh::OnMouseEvent(ui::MouseEvent* event) { | 468 void ImmersiveModeControllerAsh::OnMouseEvent(ui::MouseEvent* event) { |
| 302 if (!enabled_) | 469 if (!enabled_) |
| 303 return; | 470 return; |
| 304 | 471 |
| 305 if (event->flags() & ui::EF_IS_SYNTHESIZED) | 472 if (event->flags() & ui::EF_IS_SYNTHESIZED) |
| 306 return; | 473 return; |
| 307 | 474 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 bool active) { | 528 bool active) { |
| 362 // Mouse hover should not initiate revealing the top-of-window views while | 529 // Mouse hover should not initiate revealing the top-of-window views while |
| 363 // |native_window_| is inactive. | 530 // |native_window_| is inactive. |
| 364 top_timer_.Stop(); | 531 top_timer_.Stop(); |
| 365 | 532 |
| 366 UpdateMouseRevealedLock(true); | 533 UpdateMouseRevealedLock(true); |
| 367 UpdateFocusRevealedLock(); | 534 UpdateFocusRevealedLock(); |
| 368 } | 535 } |
| 369 | 536 |
| 370 //////////////////////////////////////////////////////////////////////////////// | 537 //////////////////////////////////////////////////////////////////////////////// |
| 538 // Animation observer: | |
| 539 | |
| 540 void ImmersiveModeControllerAsh::OnImplicitAnimationsCompleted() { | |
| 541 if (reveal_state_ == SLIDING_OPEN) | |
| 542 OnSlideOpenAnimationCompleted(); | |
| 543 else if (reveal_state_ == SLIDING_CLOSED) | |
| 544 OnSlideClosedAnimationCompleted(); | |
| 545 } | |
| 546 | |
| 547 //////////////////////////////////////////////////////////////////////////////// | |
| 371 // Testing interface: | 548 // Testing interface: |
| 372 | 549 |
| 373 void ImmersiveModeControllerAsh::SetHideTabIndicatorsForTest(bool hide) { | 550 void ImmersiveModeControllerAsh::SetHideTabIndicatorsForTest(bool hide) { |
| 374 hide_tab_indicators_ = hide; | 551 hide_tab_indicators_ = hide; |
| 375 } | 552 } |
| 376 | 553 |
| 377 void ImmersiveModeControllerAsh::StartRevealForTest(bool hovered) { | 554 void ImmersiveModeControllerAsh::StartRevealForTest(bool hovered) { |
| 378 StartReveal(ANIMATE_NO); | 555 MaybeStartReveal(ANIMATE_NO); |
| 379 SetMouseHoveredForTest(hovered); | 556 MoveMouse(browser_view_->top_container(), hovered); |
| 557 UpdateMouseRevealedLock(false); | |
| 380 } | 558 } |
| 381 | 559 |
| 382 void ImmersiveModeControllerAsh::SetMouseHoveredForTest(bool hovered) { | 560 void ImmersiveModeControllerAsh::SetMouseHoveredForTest(bool hovered) { |
| 383 views::View* top_container = browser_view_->top_container(); | 561 MoveMouse(browser_view_->top_container(), hovered); |
| 384 gfx::Point cursor_pos; | |
| 385 if (!hovered) { | |
| 386 int bottom_edge = top_container->bounds().bottom(); | |
| 387 cursor_pos = gfx::Point(0, bottom_edge + 100); | |
| 388 } | |
| 389 views::View::ConvertPointToScreen(top_container, &cursor_pos); | |
| 390 aura::Env::GetInstance()->set_last_mouse_location(cursor_pos); | |
| 391 | |
| 392 UpdateMouseRevealedLock(false); | 562 UpdateMouseRevealedLock(false); |
| 393 } | 563 } |
| 394 | 564 |
| 395 //////////////////////////////////////////////////////////////////////////////// | 565 //////////////////////////////////////////////////////////////////////////////// |
| 396 // private: | 566 // private: |
| 397 | 567 |
| 398 void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { | 568 void ImmersiveModeControllerAsh::EnableWindowObservers(bool enable) { |
| 399 if (!native_window_) { | 569 if (!native_window_) { |
| 400 DCHECK(!enable) << "ImmersiveModeControllerAsh not initialized"; | 570 DCHECK(!enable) << "ImmersiveModeControllerAsh not initialized"; |
| 401 return; | 571 return; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 412 focus_manager->RemoveFocusChangeListener(this); | 582 focus_manager->RemoveFocusChangeListener(this); |
| 413 } | 583 } |
| 414 | 584 |
| 415 if (enable) | 585 if (enable) |
| 416 native_window_->AddPreTargetHandler(this); | 586 native_window_->AddPreTargetHandler(this); |
| 417 else | 587 else |
| 418 native_window_->RemovePreTargetHandler(this); | 588 native_window_->RemovePreTargetHandler(this); |
| 419 | 589 |
| 420 // The window observer adds and removes itself from the native window. | 590 // The window observer adds and removes itself from the native window. |
| 421 window_observer_.reset(enable ? new WindowObserver(this) : NULL); | 591 window_observer_.reset(enable ? new WindowObserver(this) : NULL); |
| 592 | |
| 593 if (!enable) | |
| 594 StopObservingImplicitAnimations(); | |
| 422 } | 595 } |
| 423 | 596 |
| 424 void ImmersiveModeControllerAsh::UpdateMouseRevealedLock(bool maybe_drag) { | 597 void ImmersiveModeControllerAsh::UpdateMouseRevealedLock(bool maybe_drag) { |
| 425 if (!enabled_) | 598 if (!enabled_) |
| 426 return; | 599 return; |
| 427 | 600 |
| 428 // Hover cannot initiate a reveal when the top-of-window views are sliding | 601 // Hover cannot initiate a reveal when the top-of-window views are sliding |
| 429 // closed or are closed. (With the exception of hovering at y = 0 which is | 602 // closed or are closed. (With the exception of hovering at y = 0 which is |
| 430 // handled in OnMouseEvent() ). | 603 // handled in OnMouseEvent() ). |
| 431 if (reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED) | 604 if (reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 return 0; | 672 return 0; |
| 500 case ANIMATE_SLOW: | 673 case ANIMATE_SLOW: |
| 501 return kRevealSlowAnimationDurationMs; | 674 return kRevealSlowAnimationDurationMs; |
| 502 case ANIMATE_FAST: | 675 case ANIMATE_FAST: |
| 503 return kRevealFastAnimationDurationMs; | 676 return kRevealFastAnimationDurationMs; |
| 504 } | 677 } |
| 505 NOTREACHED(); | 678 NOTREACHED(); |
| 506 return 0; | 679 return 0; |
| 507 } | 680 } |
| 508 | 681 |
| 509 void ImmersiveModeControllerAsh::MaybeStartReveal() { | 682 void ImmersiveModeControllerAsh::MaybeStartReveal(Animate animate) { |
| 510 if (enabled_ && reveal_state_ != REVEALED) | 683 if (!enabled_) |
| 511 StartReveal(ANIMATE_FAST); | 684 return; |
| 512 } | |
| 513 | 685 |
| 514 void ImmersiveModeControllerAsh::StartReveal(Animate animate) { | 686 // Callers with ANIMATE_NO expect this function to synchronously reveal the |
| 515 if (reveal_state_ == CLOSED) { | 687 // top-of-window views. In particular, this property is used to terminate the |
| 516 reveal_state_ = SLIDING_OPEN; | 688 // reveal animation if an equivalent animation for the anchored widgets |
| 689 // cannot be created. | |
| 690 if (reveal_state_ == REVEALED || | |
| 691 (reveal_state_ == SLIDING_OPEN && animate != ANIMATE_NO)) { | |
| 692 return; | |
| 693 } | |
| 694 | |
| 695 RevealState previous_reveal_state = reveal_state_; | |
| 696 reveal_state_ = SLIDING_OPEN; | |
| 697 if (previous_reveal_state == CLOSED) { | |
| 517 // Turn on layer painting so we can smoothly animate. | 698 // Turn on layer painting so we can smoothly animate. |
| 518 EnablePaintToLayer(true); | 699 EnablePaintToLayer(true); |
| 519 | 700 |
| 520 // Ensure window caption buttons are updated and the view bounds are | 701 // Ensure window caption buttons are updated and the view bounds are |
| 521 // computed at normal (non-immersive-style) size. | 702 // computed at normal (non-immersive-style) size. |
| 522 LayoutBrowserView(false); | 703 LayoutBrowserView(false); |
| 523 | 704 |
| 705 // Do not do any more processing if LayoutBrowserView() changed | |
| 706 // |reveal_state_|. | |
| 707 if (reveal_state_ != SLIDING_OPEN) | |
| 708 return; | |
| 709 | |
| 524 if (animate != ANIMATE_NO) { | 710 if (animate != ANIMATE_NO) { |
| 525 // Now that we have a layer, move it to the initial offscreen position. | 711 // Now that we have a layer, move it to the initial offscreen position. |
| 526 ui::Layer* layer = browser_view_->top_container()->layer(); | 712 ui::Layer* layer = browser_view_->top_container()->layer(); |
| 527 gfx::Transform transform; | 713 gfx::Transform transform; |
| 528 transform.Translate(0, -layer->bounds().height() + kAnimationOffsetY); | 714 transform.Translate(0, -layer->bounds().height() + kAnimationOffsetY); |
| 529 layer->SetTransform(transform); | 715 layer->SetTransform(transform); |
| 716 | |
| 717 typedef std::set<views::Widget*> WidgetSet; | |
| 718 const WidgetSet& visible_widgets = | |
| 719 anchored_widget_manager_->visible_anchored_widgets(); | |
| 720 for (WidgetSet::const_iterator it = visible_widgets.begin(); | |
| 721 it != visible_widgets.end(); ++it) { | |
| 722 (*it)->GetNativeWindow()->SetTransform(transform); | |
| 723 } | |
| 530 } | 724 } |
| 531 // Slide in the reveal view. | |
| 532 AnimateSlideOpen(GetAnimationDuration(animate)); | |
| 533 } else if (reveal_state_ == SLIDING_CLOSED) { | |
| 534 reveal_state_ = SLIDING_OPEN; | |
| 535 // Reverse the animation. | |
| 536 AnimateSlideOpen(GetAnimationDuration(animate)); | |
| 537 } | 725 } |
| 726 // Slide in the reveal view. | |
| 727 DoAnimation(gfx::Transform(), GetAnimationDuration(animate)); | |
| 538 } | 728 } |
| 539 | 729 |
| 540 void ImmersiveModeControllerAsh::EnablePaintToLayer(bool enable) { | 730 void ImmersiveModeControllerAsh::EnablePaintToLayer(bool enable) { |
| 541 browser_view_->top_container()->SetPaintToLayer(enable); | 731 browser_view_->top_container()->SetPaintToLayer(enable); |
| 542 | 732 |
| 543 // Views software compositing is not fully layer aware. If the bookmark bar | 733 // Views software compositing is not fully layer aware. If the bookmark bar |
| 544 // is detached while the top container layer slides on or off the screen, | 734 // is detached while the top container layer slides on or off the screen, |
| 545 // the pixels that become exposed are the remnants of the last software | 735 // the pixels that become exposed are the remnants of the last software |
| 546 // composite of the BrowserView, not the freshly-exposed bookmark bar. | 736 // composite of the BrowserView, not the freshly-exposed bookmark bar. |
| 547 // Force the bookmark bar to paint to a layer so the views composite | 737 // Force the bookmark bar to paint to a layer so the views composite |
| 548 // properly. The infobar container does not need this treatment because | 738 // properly. The infobar container does not need this treatment because |
| 549 // BrowserView::PaintChildren() always draws it last when it is visible. | 739 // BrowserView::PaintChildren() always draws it last when it is visible. |
| 550 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar(); | 740 BookmarkBarView* bookmark_bar = browser_view_->bookmark_bar(); |
| 551 if (!bookmark_bar) | 741 if (!bookmark_bar) |
| 552 return; | 742 return; |
| 553 if (enable && bookmark_bar->IsDetached()) | 743 if (enable && bookmark_bar->IsDetached()) |
| 554 bookmark_bar->SetPaintToLayer(true); | 744 bookmark_bar->SetPaintToLayer(true); |
| 555 else | 745 else |
| 556 bookmark_bar->SetPaintToLayer(false); | 746 bookmark_bar->SetPaintToLayer(false); |
| 557 } | 747 } |
| 558 | 748 |
| 559 void ImmersiveModeControllerAsh::LayoutBrowserView(bool immersive_style) { | 749 void ImmersiveModeControllerAsh::LayoutBrowserView(bool immersive_style) { |
| 560 // Update the window caption buttons. | 750 // Update the window caption buttons. |
| 561 browser_view_->GetWidget()->non_client_view()->frame_view()-> | 751 browser_view_->GetWidget()->non_client_view()->frame_view()-> |
| 562 ResetWindowControls(); | 752 ResetWindowControls(); |
| 563 browser_view_->tabstrip()->SetImmersiveStyle(immersive_style); | 753 browser_view_->tabstrip()->SetImmersiveStyle(immersive_style); |
| 564 browser_view_->frame()->GetRootView()->Layout(); | 754 browser_view_->frame()->GetRootView()->Layout(); |
| 565 } | 755 } |
| 566 | 756 |
| 567 void ImmersiveModeControllerAsh::AnimateSlideOpen(int duration_ms) { | 757 void ImmersiveModeControllerAsh::OnSlideOpenAnimationCompleted() { |
| 568 ui::Layer* layer = browser_view_->top_container()->layer(); | 758 DCHECK_EQ(SLIDING_OPEN, reveal_state_); |
| 569 // Stop any slide closed animation in progress. | 759 reveal_state_ = REVEALED; |
| 570 layer->GetAnimator()->AbortAllAnimations(); | |
| 571 | 760 |
| 572 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); | 761 // The user may not have moved the mouse since the reveal was initiated. |
| 573 settings.AddObserver(slide_open_observer_.get()); | 762 // Update the revealed lock to reflect the mouse's current state. |
| 574 settings.SetTweenType(ui::Tween::EASE_OUT); | 763 UpdateMouseRevealedLock(true); |
| 575 settings.SetTransitionDuration( | |
| 576 base::TimeDelta::FromMilliseconds(duration_ms)); | |
| 577 layer->SetTransform(gfx::Transform()); | |
| 578 } | 764 } |
| 579 | 765 |
| 580 void ImmersiveModeControllerAsh::OnSlideOpenAnimationCompleted() { | 766 void ImmersiveModeControllerAsh::MaybeEndReveal(Animate animate) { |
| 581 if (reveal_state_ == SLIDING_OPEN) { | 767 if (!enabled_ || revealed_lock_count_ != 0) |
| 582 reveal_state_ = REVEALED; | 768 return; |
| 583 | 769 |
| 584 // The user may not have moved the mouse since the reveal was initiated. | 770 // Callers with ANIMATE_NO expect this function to synchronously close the |
| 585 // Update the revealed lock to reflect the mouse's current state. | 771 // top-of-window views. |
| 586 UpdateMouseRevealedLock(true); | 772 if (reveal_state_ == CLOSED || |
| 773 (reveal_state_ == SLIDING_CLOSED && animate != ANIMATE_NO)) { | |
| 774 return; | |
| 775 } | |
| 776 | |
| 777 // Visible anchored widgets keep the top-of-window views revealed. | |
| 778 DCHECK(anchored_widget_manager_->visible_anchored_widgets().empty()); | |
| 779 | |
| 780 reveal_state_ = SLIDING_CLOSED; | |
| 781 int duration_ms = GetAnimationDuration(animate); | |
| 782 if (duration_ms > 0) { | |
| 783 // The bookmark bar may have become detached during the reveal so ensure | |
| 784 // layers are available. This is a no-op for the top container. | |
| 785 EnablePaintToLayer(true); | |
| 786 | |
| 787 ui::Layer* top_container_layer = browser_view_->top_container()->layer(); | |
| 788 gfx::Transform target_transform; | |
| 789 target_transform.Translate(0, | |
| 790 -top_container_layer->bounds().height() + kAnimationOffsetY); | |
| 791 | |
| 792 DoAnimation(target_transform, duration_ms); | |
| 793 } else { | |
| 794 OnSlideClosedAnimationCompleted(); | |
| 587 } | 795 } |
| 588 } | 796 } |
| 589 | 797 |
| 590 void ImmersiveModeControllerAsh::MaybeEndReveal(Animate animate) { | 798 void ImmersiveModeControllerAsh::OnSlideClosedAnimationCompleted() { |
| 591 if (enabled_ && reveal_state_ != CLOSED && revealed_lock_count_ == 0) | 799 DCHECK_EQ(SLIDING_CLOSED, reveal_state_); |
| 592 EndReveal(animate); | 800 reveal_state_ = CLOSED; |
| 801 // Layers aren't needed after animation completes. | |
| 802 EnablePaintToLayer(false); | |
| 803 // Update tabstrip for closed state. | |
| 804 LayoutBrowserView(true); | |
| 593 } | 805 } |
| 594 | 806 |
| 595 void ImmersiveModeControllerAsh::EndReveal(Animate animate) { | 807 void ImmersiveModeControllerAsh::DoAnimation( |
| 596 if (reveal_state_ == SLIDING_OPEN || reveal_state_ == REVEALED) { | 808 const gfx::Transform& target_transform, |
| 597 reveal_state_ = SLIDING_CLOSED; | 809 int duration_ms) { |
| 598 int duration_ms = GetAnimationDuration(animate); | 810 StopObservingImplicitAnimations(); |
| 599 if (duration_ms > 0) { | 811 DoLayerAnimation(browser_view_->top_container()->layer(), target_transform, |
| 600 // Bookmark bar have become detached during the reveal so ensure | 812 duration_ms, this); |
| 601 // layers are available. This is a no-op for top container. | 813 |
| 602 EnablePaintToLayer(true); | 814 typedef std::set<views::Widget*> WidgetSet; |
| 603 AnimateSlideClosed(duration_ms); | 815 const WidgetSet& visible_widgets = |
| 604 } else { | 816 anchored_widget_manager_->visible_anchored_widgets(); |
| 605 OnSlideClosedAnimationCompleted(); | 817 for (WidgetSet::const_iterator it = visible_widgets.begin(); |
| 606 } | 818 it != visible_widgets.end(); ++it) { |
| 819 // The anchored widget's bounds are set to the target bounds right when the | |
| 820 // animation starts. The transform is used to animate the widget's position. | |
| 821 // Using the target bounds allows us to "stay anchored" if other code | |
| 822 // changes the widget bounds in the middle of the animation. (This is the | |
| 823 // case if the fullscreen exit bubble type is changed during the immersive | |
| 824 // reveal animation). | |
| 825 DoLayerAnimation((*it)->GetNativeWindow()->layer(), gfx::Transform(), | |
| 826 duration_ms, NULL); | |
| 607 } | 827 } |
| 608 } | 828 } |
| 609 | 829 |
| 610 void ImmersiveModeControllerAsh::AnimateSlideClosed(int duration_ms) { | 830 void ImmersiveModeControllerAsh::DoLayerAnimation( |
| 611 // Stop any slide open animation in progress, but don't skip to the end. This | 831 ui::Layer* layer, |
| 612 // avoids a visual "pop" when starting a hide in the middle of a show. | 832 const gfx::Transform& target_transform, |
| 613 ui::Layer* layer = browser_view_->top_container()->layer(); | 833 int duration_ms, |
| 614 layer->GetAnimator()->AbortAllAnimations(); | 834 ui::ImplicitAnimationObserver* observer) { |
| 615 | |
| 616 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); | 835 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); |
| 617 settings.SetTweenType(ui::Tween::EASE_OUT); | 836 settings.SetTweenType(ui::Tween::EASE_OUT); |
| 618 settings.SetTransitionDuration( | 837 settings.SetTransitionDuration( |
| 619 base::TimeDelta::FromMilliseconds(duration_ms)); | 838 base::TimeDelta::FromMilliseconds(duration_ms)); |
| 620 settings.AddObserver(slide_closed_observer_.get()); | 839 settings.SetPreemptionStrategy( |
| 621 gfx::Transform transform; | 840 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 622 transform.Translate(0, -layer->bounds().height() + kAnimationOffsetY); | 841 if (observer) |
| 623 layer->SetTransform(transform); | 842 settings.AddObserver(observer); |
| 843 layer->SetTransform(target_transform); | |
| 624 } | 844 } |
| 625 | |
| 626 void ImmersiveModeControllerAsh::OnSlideClosedAnimationCompleted() { | |
| 627 if (reveal_state_ == SLIDING_CLOSED) { | |
| 628 reveal_state_ = CLOSED; | |
| 629 // Layers aren't needed after animation completes. | |
| 630 EnablePaintToLayer(false); | |
| 631 // Update tabstrip for closed state. | |
| 632 LayoutBrowserView(true); | |
| 633 } | |
| 634 } | |
| OLD | NEW |