Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/ash/tab_scrubber.h" | 5 #include "chrome/browser/ui/views/ash/tab_scrubber.h" |
| 6 | 6 |
| 7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
| 8 #include "ash/wm/window_util.h" | 8 #include "ash/wm/window_util.h" |
| 9 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
| 10 #include "chrome/browser/ui/browser_finder.h" | 10 #include "chrome/browser/ui/browser_finder.h" |
| 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 12 #include "chrome/browser/ui/views/frame/browser_view.h" | 12 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 13 #include "chrome/browser/ui/views/immersive_mode_controller.h" | |
| 13 #include "chrome/browser/ui/views/tabs/tab.h" | 14 #include "chrome/browser/ui/views/tabs/tab.h" |
| 14 #include "chrome/browser/ui/views/tabs/tab_strip.h" | 15 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
| 15 #include "chrome/common/chrome_notification_types.h" | 16 #include "chrome/common/chrome_notification_types.h" |
| 17 #include "content/public/browser/notification_service.h" | |
| 16 #include "content/public/browser/notification_source.h" | 18 #include "content/public/browser/notification_source.h" |
| 17 #include "ui/aura/window.h" | 19 #include "ui/aura/window.h" |
| 18 #include "ui/base/events/event.h" | 20 #include "ui/base/events/event.h" |
| 19 #include "ui/base/events/event_utils.h" | 21 #include "ui/base/events/event_utils.h" |
| 22 #include "ui/views/controls/glow_hover_controller.h" | |
| 20 | 23 |
| 21 namespace { | 24 namespace { |
| 22 Tab* GetTabAt(TabStrip* tab_strip, gfx::Point point) { | 25 const int64 kActivationDelayMS = 200; |
| 23 for (int i = 0; i < tab_strip->tab_count(); ++i) { | 26 const int64 kCancelImmersiveRevelDelayMS = 200; |
| 24 Tab* tab = tab_strip->tab_at(i); | |
| 25 if (tab_strip->tab_at(i)->bounds().Contains(point)) | |
| 26 return tab; | |
| 27 } | |
| 28 return NULL; | |
| 29 } | |
| 30 | |
| 31 const int kInitialTabOffset = 10; | |
| 32 } | 27 } |
| 33 | 28 |
| 34 // static | 29 // static |
| 35 TabScrubber* TabScrubber::GetInstance() { | 30 TabScrubber* TabScrubber::GetInstance() { |
| 36 static TabScrubber* instance = NULL; | 31 static TabScrubber* instance = NULL; |
| 37 if (!instance) | 32 if (!instance) |
| 38 instance = new TabScrubber(); | 33 instance = new TabScrubber(); |
| 39 return instance; | 34 return instance; |
| 40 } | 35 } |
| 41 | 36 |
| 42 TabScrubber::TabScrubber() | 37 TabScrubber::TabScrubber() |
| 43 : scrubbing_(false), | 38 : scrubbing_(false), |
| 44 browser_(NULL), | 39 browser_(NULL), |
| 45 scroll_x_(-1), | 40 swipe_x_(-1), |
| 46 scroll_y_(-1) { | 41 swipe_y_(-1), |
| 42 overridden_tab_(-1), | |
| 43 activate_timer_(true, false), | |
| 44 activation_delay_(base::TimeDelta::FromMilliseconds(kActivationDelayMS)), | |
| 45 should_cancel_immersive_reveal_(false), | |
| 46 cancel_immersive_reveal_timer_(true, false), | |
| 47 weak_ptr_factory_(this) { | |
| 47 ash::Shell::GetInstance()->AddPreTargetHandler(this); | 48 ash::Shell::GetInstance()->AddPreTargetHandler(this); |
|
sky
2013/01/22 18:05:01
Should this be removed at some point?
DaveMoore
2013/01/27 21:21:54
I thought the registrar takes care of that upon de
| |
| 49 registrar_.Add( | |
| 50 this, | |
| 51 chrome::NOTIFICATION_BROWSER_CLOSING, | |
| 52 content::NotificationService::AllSources()); | |
| 48 } | 53 } |
| 49 | 54 |
| 50 TabScrubber::~TabScrubber() { | 55 TabScrubber::~TabScrubber() { |
| 51 } | 56 } |
| 52 | 57 |
| 58 // static | |
| 59 const gfx::Point TabScrubber::GetStartPoint( | |
|
sky
2013/01/22 18:05:01
Make order match header.
DaveMoore
2013/01/27 21:21:54
Done.
| |
| 60 TabStrip* tab_strip, | |
| 61 int index, | |
| 62 Direction direction) { | |
| 63 int initial_tab_offset = Tab::GetMiniWidth() / 2; | |
| 64 gfx::Rect tab_bounds = tab_strip->tab_at(index)->bounds(); | |
|
sky
2013/01/22 18:05:01
If an animation is occurring bounds() is going to
DaveMoore
2013/01/27 21:21:54
Is there some way to get the right location then?
sky
2013/01/28 19:18:52
You can use ideal_bounds(index) to get the ideal b
| |
| 65 float x = direction == LEFT ? | |
| 66 tab_bounds.x() + initial_tab_offset : | |
| 67 tab_bounds.right() - initial_tab_offset; | |
| 68 return gfx::Point(x, tab_bounds.CenterPoint().y()); | |
| 69 } | |
| 70 | |
| 53 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) { | 71 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) { |
| 54 if (event->type() == ui::ET_SCROLL_FLING_CANCEL) { | 72 if (event->type() == ui::ET_SCROLL_FLING_CANCEL || |
| 55 if (scrubbing_) | 73 event->type() == ui::ET_SCROLL_FLING_START) { |
| 56 StopScrubbing(); | 74 FinishScrub(true); |
| 75 CancelImmersiveReveal(); | |
| 57 return; | 76 return; |
| 58 } | 77 } |
| 59 | 78 |
| 60 if (event->finger_count() != 3 || | 79 if (event->finger_count() != 3) |
| 61 event->type() != ui::ET_SCROLL) | |
| 62 return; | 80 return; |
| 63 | 81 |
| 64 Browser* browser = GetActiveBrowser(); | 82 Browser* browser = GetActiveBrowser(); |
| 65 if (!browser || (browser_ && browser != browser_)) { | 83 if (!browser || (browser_ && browser != browser_)) { |
| 66 if (scrubbing_) | 84 FinishScrub(false); |
| 67 StopScrubbing(); | |
| 68 return; | 85 return; |
| 69 } | 86 } |
| 70 | 87 |
| 88 event->StopPropagation(); | |
| 89 float x_offset = event->x_offset(); | |
| 71 BrowserView* browser_view = | 90 BrowserView* browser_view = |
| 72 BrowserView::GetBrowserViewForNativeWindow( | 91 BrowserView::GetBrowserViewForNativeWindow( |
| 73 browser->window()->GetNativeWindow()); | 92 browser->window()->GetNativeWindow()); |
| 74 TabStrip* tab_strip = browser_view->tabstrip(); | 93 TabStrip* tab_strip = browser_view->tabstrip(); |
| 75 | 94 |
| 76 float x_offset = -event->x_offset(); | 95 if (!ui::IsNaturalScrollEnabled()) |
| 96 x_offset = -x_offset; | |
| 97 int last_tab_index = overridden_tab_ == -1 ? | |
|
sky
2013/01/22 18:05:01
What happens if overrideen_tab_ is no longer a val
DaveMoore
2013/01/27 21:21:54
Added check above and abort if not valid.
On 2013/
| |
| 98 browser->tab_strip_model()->active_index() : overridden_tab_; | |
| 77 if (!scrubbing_) { | 99 if (!scrubbing_) { |
| 100 swipe_direction_ = (x_offset < 0) ? LEFT : RIGHT; | |
| 101 const gfx::Point start_point = | |
| 102 GetStartPoint(tab_strip, | |
| 103 browser->tab_strip_model()->active_index(), | |
| 104 swipe_direction_); | |
| 105 browser_ = browser; | |
| 78 scrubbing_ = true; | 106 scrubbing_ = true; |
| 79 browser_ = browser; | 107 |
| 80 Tab* initial_tab = | 108 swipe_x_ = start_point.x(); |
| 81 tab_strip->tab_at(browser_->tab_strip_model()->active_index()); | 109 swipe_y_ = start_point.y(); |
| 82 scroll_x_ = initial_tab->x(); | 110 ImmersiveModeController* immersive_controller = |
| 83 scroll_x_ += (x_offset < 0) ? | 111 browser_view->immersive_mode_controller(); |
| 84 kInitialTabOffset : initial_tab->width() - kInitialTabOffset; | 112 if (cancel_immersive_reveal_timer_.IsRunning()) |
| 85 scroll_y_ = initial_tab->height() / 2; | 113 cancel_immersive_reveal_timer_.Stop(); |
| 86 registrar_.Add( | 114 if (immersive_controller->enabled() && |
| 87 this, | 115 !immersive_controller->IsRevealed()) { |
| 88 chrome::NOTIFICATION_BROWSER_CLOSING, | 116 immersive_controller->MaybeStartReveal(); |
| 89 content::Source<Browser>(browser_)); | 117 should_cancel_immersive_reveal_ = true; |
| 118 } | |
| 119 } else if (overridden_tab_ == -1) { | |
| 120 Direction direction = (x_offset < 0) ? LEFT : RIGHT; | |
| 121 if (direction != swipe_direction_) { | |
| 122 const gfx::Point start_point = | |
| 123 GetStartPoint(tab_strip, | |
| 124 browser->tab_strip_model()->active_index(), | |
| 125 swipe_direction_); | |
| 126 swipe_x_ = start_point.x(); | |
| 127 swipe_y_ = start_point.y(); | |
| 128 swipe_direction_ = direction; | |
| 129 } | |
| 90 } | 130 } |
| 91 | 131 |
| 92 if (ui::IsNaturalScrollEnabled()) | 132 swipe_x_ += x_offset; |
| 93 scroll_x_ += event->x_offset(); | |
| 94 else | |
| 95 scroll_x_ -= event->x_offset(); | |
| 96 Tab* first_tab = tab_strip->tab_at(0); | 133 Tab* first_tab = tab_strip->tab_at(0); |
| 134 int first_tab_center = first_tab->bounds().CenterPoint().x(); | |
| 97 Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1); | 135 Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1); |
| 98 if (scroll_x_ < first_tab->x()) | 136 int last_tab_tab_center = last_tab->bounds().CenterPoint().x(); |
| 99 scroll_x_ = first_tab->x(); | 137 if (swipe_x_ < first_tab_center) |
| 100 if (scroll_x_ > last_tab->bounds().right()) | 138 swipe_x_ = first_tab_center; |
| 101 scroll_x_ = last_tab->bounds().right(); | 139 if (swipe_x_ > last_tab_tab_center) |
| 140 swipe_x_ = last_tab_tab_center; | |
| 102 | 141 |
| 103 gfx::Point tab_point(scroll_x_, scroll_y_); | 142 Tab* initial_tab = tab_strip->tab_at(last_tab_index); |
| 104 Tab* new_tab = GetTabAt(tab_strip, tab_point); | 143 gfx::Point tab_point(swipe_x_, swipe_y_); |
| 105 if (new_tab && !new_tab->IsActive()) { | 144 views::View::ConvertPointToTarget(tab_strip, initial_tab, &tab_point); |
| 106 int new_index = tab_strip->GetModelIndexOfTab(new_tab); | 145 Tab* new_tab = tab_strip->GetTabAt(initial_tab, tab_point); |
| 107 browser->tab_strip_model()->ActivateTabAt(new_index, true); | 146 if (!new_tab) |
| 147 return; | |
| 148 | |
| 149 int new_index = tab_strip->GetModelIndexOfTab(new_tab); | |
| 150 if (new_index != overridden_tab_) { | |
| 151 if (activate_timer_.IsRunning()) { | |
| 152 activate_timer_.Reset(); | |
| 153 } else { | |
| 154 activate_timer_.Start(FROM_HERE, | |
| 155 activation_delay_, | |
| 156 base::Bind(&TabScrubber::FinishScrub, | |
| 157 weak_ptr_factory_.GetWeakPtr(), | |
| 158 true)); | |
| 159 } | |
| 108 } | 160 } |
| 109 | 161 |
| 110 event->StopPropagation(); | 162 if (overridden_tab_ != new_index) { |
| 163 if (overridden_tab_ != -1) | |
| 164 tab_strip->tab_at(overridden_tab_)->hover_controller()->HideImmediately(); | |
| 165 if (new_index == browser->tab_strip_model()->active_index()) { | |
| 166 overridden_tab_ = -1; | |
| 167 } else { | |
| 168 overridden_tab_ = new_index; | |
| 169 new_tab->hover_controller()->Show(views::GlowHoverController::PRONOUNCED); | |
| 170 } | |
| 171 } | |
| 172 if (overridden_tab_ != -1) { | |
| 173 gfx::Point hover_point(swipe_x_, swipe_y_); | |
| 174 views::View::ConvertPointToTarget(tab_strip, new_tab, &hover_point); | |
| 175 new_tab->hover_controller()->SetLocation(hover_point); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 void TabScrubber::FinishScrub(bool activate) { | |
| 180 if (activate_timer_.IsRunning()) | |
| 181 activate_timer_.Stop(); | |
| 182 | |
| 183 if (browser_) { | |
| 184 BrowserView* browser_view = | |
| 185 BrowserView::GetBrowserViewForNativeWindow( | |
| 186 browser_->window()->GetNativeWindow()); | |
| 187 if (activate && overridden_tab_ != -1) { | |
| 188 TabStrip* tab_strip = browser_view->tabstrip(); | |
| 189 tab_strip->tab_at(overridden_tab_)->hover_controller()->HideImmediately(); | |
| 190 browser_->tab_strip_model()->ActivateTabAt(overridden_tab_, true); | |
| 191 } | |
| 192 if (!cancel_immersive_reveal_timer_.IsRunning() && | |
| 193 should_cancel_immersive_reveal_) { | |
| 194 cancel_immersive_reveal_timer_.Start( | |
| 195 FROM_HERE, | |
| 196 base::TimeDelta::FromMilliseconds(kCancelImmersiveRevelDelayMS), | |
| 197 base:: Bind(&TabScrubber::CancelImmersiveReveal, | |
| 198 weak_ptr_factory_.GetWeakPtr())); | |
| 199 } | |
| 200 } | |
| 201 swipe_x_ = -1; | |
| 202 swipe_y_ = -1; | |
| 203 scrubbing_ = false; | |
| 204 overridden_tab_ = -1; | |
| 205 } | |
| 206 | |
| 207 void TabScrubber::CancelImmersiveReveal() { | |
| 208 if (cancel_immersive_reveal_timer_.IsRunning()) | |
| 209 cancel_immersive_reveal_timer_.Stop(); | |
| 210 if (browser_ && should_cancel_immersive_reveal_) { | |
|
sky
2013/01/22 18:05:01
What is browser_ changes between the time you star
DaveMoore
2013/01/27 21:21:54
There already was protection against this when bro
| |
| 211 BrowserView* browser_view = | |
| 212 BrowserView::GetBrowserViewForNativeWindow( | |
| 213 browser_->window()->GetNativeWindow()); | |
| 214 browser_view->immersive_mode_controller()->CancelReveal(); | |
| 215 } | |
| 216 should_cancel_immersive_reveal_ = false; | |
| 111 } | 217 } |
| 112 | 218 |
| 113 void TabScrubber::Observe(int type, | 219 void TabScrubber::Observe(int type, |
| 114 const content::NotificationSource& source, | 220 const content::NotificationSource& source, |
| 115 const content::NotificationDetails& details) { | 221 const content::NotificationDetails& details) { |
| 116 DCHECK(type == chrome::NOTIFICATION_BROWSER_CLOSING && | 222 if (content::Source<Browser>(source).ptr() == browser_) |
| 117 content::Source<Browser>(source).ptr() == browser_); | 223 FinishScrub(false); |
| 118 StopScrubbing(); | 224 browser_ = NULL; |
| 119 } | 225 } |
| 120 | 226 |
| 121 Browser* TabScrubber::GetActiveBrowser() { | 227 Browser* TabScrubber::GetActiveBrowser() { |
| 122 aura::Window* active_window = ash::wm::GetActiveWindow(); | 228 aura::Window* active_window = ash::wm::GetActiveWindow(); |
| 123 if (!active_window) | 229 if (!active_window) |
| 124 return NULL; | 230 return NULL; |
| 125 | 231 |
| 126 Browser* browser = chrome::FindBrowserWithWindow(active_window); | 232 Browser* browser = chrome::FindBrowserWithWindow(active_window); |
| 127 if (!browser || browser->type() != Browser::TYPE_TABBED) | 233 if (!browser || browser->type() != Browser::TYPE_TABBED) |
| 128 return NULL; | 234 return NULL; |
| 129 | 235 |
| 130 return browser; | 236 return browser; |
| 131 } | 237 } |
| 132 | |
| 133 void TabScrubber::StopScrubbing() { | |
| 134 if (!scrubbing_) | |
| 135 return; | |
| 136 | |
| 137 registrar_.Remove( | |
| 138 this, | |
| 139 chrome::NOTIFICATION_BROWSER_CLOSING, | |
| 140 content::Source<Browser>(browser_)); | |
| 141 scrubbing_ = false; | |
| 142 browser_ = NULL; | |
| 143 } | |
| OLD | NEW |