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
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
6 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
10 #include "base/compiler_specific.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/timer/timer.h"
13 #include "chrome/browser/ui/views/tabs/tab.h"
14 #include "chrome/browser/ui/views/tabs/tab_controller.h"
15 #include "ui/gfx/animation/animation_container.h"
16 #include "ui/gfx/point.h"
17 #include "ui/gfx/rect.h"
18 #include "ui/views/animation/bounds_animator.h"
19 #include "ui/views/controls/button/image_button.h"
20 #include "ui/views/mouse_watcher.h"
21 #include "ui/views/view.h"
22 #include "ui/views/view_model.h"
23 #include "ui/views/view_targeter_delegate.h"
26 class StackedTabStripLayout;
28 class TabDragController;
29 class TabStripController;
30 class TabStripObserver;
33 class ListSelectionModel;
40 ///////////////////////////////////////////////////////////////////////////////
44 // A View that represents the TabStripModel. The TabStrip has the
45 // following responsibilities:
46 // - It implements the TabStripModelObserver interface, and acts as a
47 // container for Tabs, and is also responsible for creating them.
48 // - It takes part in Tab Drag & Drop with Tab, TabDragHelper and
49 // DraggedTab, focusing on tasks that require reshuffling other tabs
50 // in response to dragged tabs.
52 ///////////////////////////////////////////////////////////////////////////////
53 class TabStrip : public views::View,
54 public views::ButtonListener,
55 public views::MouseWatcherListener,
56 public views::ViewTargeterDelegate,
57 public TabController {
59 static const char kViewClassName[];
61 // Horizontal offset for the new tab button to bring it closer to the
63 static const int kNewTabButtonHorizontalOffset;
65 // The vertical offset of the tab strip button. This offset applies only to
67 static const int kNewTabButtonVerticalOffset;
69 // The size of the new tab button must be hardcoded because we need to be
70 // able to lay it out before we are able to get its image from the
71 // ui::ThemeProvider. It also makes sense to do this, because the size of the
72 // new tab button should not need to be calculated dynamically.
73 static const int kNewTabButtonAssetWidth;
74 static const int kNewTabButtonAssetHeight;
76 explicit TabStrip(TabStripController* controller);
79 // Add and remove observers to changes within this TabStrip.
80 void AddObserver(TabStripObserver* observer);
81 void RemoveObserver(TabStripObserver* observer);
83 // If |adjust_layout| is true the stacked layout changes based on whether the
84 // user uses a mouse or a touch device with the tabstrip.
85 void set_adjust_layout(bool adjust_layout) { adjust_layout_ = adjust_layout; }
87 // |stacked_layout_| defines what should happen when the tabs won't fit at
88 // their ideal size. When |stacked_layout_| is true the tabs are always sized
89 // to their ideal size and stacked on top of each other so that only a certain
90 // set of tabs are visible. This is used when the user uses a touch device.
91 // When |stacked_layout_| is false the tabs shrink to accommodate the
92 // available space. This is the default.
93 bool stacked_layout() const { return stacked_layout_; }
95 // Sets |stacked_layout_| and animates if necessary.
96 void SetStackedLayout(bool stacked_layout);
98 // Returns the bounds of the new tab button.
99 gfx::Rect GetNewTabButtonBounds();
101 // Returns true if the new tab button should be sized to the top of the tab
103 bool SizeTabButtonToTopOfTabStrip();
105 // Starts highlighting the tab at the specified index.
106 void StartHighlight(int model_index);
108 // Stops all tab higlighting.
109 void StopAllHighlighting();
111 // Adds a tab at the specified index.
112 void AddTabAt(int model_index, const TabRendererData& data, bool is_active);
115 void MoveTab(int from_model_index,
117 const TabRendererData& data);
119 // Removes a tab at the specified index.
120 void RemoveTabAt(int model_index);
122 // Sets the tab data at the specified model index.
123 void SetTabData(int model_index, const TabRendererData& data);
125 // Returns true if the tab is not partly or fully clipped (due to overflow),
126 // and the tab couldn't become partly clipped due to changing the selected tab
127 // (for example, if currently the strip has the last tab selected, and
128 // changing that to the first tab would cause |tab| to be pushed over enough
130 bool ShouldTabBeVisible(const Tab* tab) const;
132 // Invoked from the controller when the close initiates from the TabController
133 // (the user clicked the tab close button or middle clicked the tab). This is
134 // invoked from Close. Because of unload handlers Close is not always
135 // immediately followed by RemoveTabAt.
136 void PrepareForCloseAt(int model_index, CloseTabSource source);
138 // Invoked when the selection changes from |old_selection| to
140 void SetSelection(const ui::ListSelectionModel& old_selection,
141 const ui::ListSelectionModel& new_selection);
143 // Invoked when the title of a tab changes and the tab isn't loading.
144 void TabTitleChangedNotLoading(int model_index);
146 // Retrieves the ideal bounds for the Tab at the specified index.
147 const gfx::Rect& ideal_bounds(int tab_data_index) {
148 return tabs_.ideal_bounds(tab_data_index);
151 // Returns the Tab at |index|.
152 Tab* tab_at(int index) const { return tabs_.view_at(index); }
154 // Returns the index of the specified tab in the model coordinate system, or
155 // -1 if tab is closing or not valid.
156 int GetModelIndexOfTab(const Tab* tab) const;
158 // Gets the number of Tabs in the tab strip.
159 int tab_count() const { return tabs_.view_size(); }
161 // Cover method for TabStripController::GetCount.
162 int GetModelCount() const;
164 // Cover method for TabStripController::IsValidIndex.
165 bool IsValidModelIndex(int model_index) const;
167 TabStripController* controller() const { return controller_.get(); }
169 // Returns true if a drag session is currently active.
170 bool IsDragSessionActive() const;
172 // Returns true if a tab is being dragged into this tab strip.
173 bool IsActiveDropTarget() const;
175 // Returns true if the tab strip is editable. Returns false if the tab strip
176 // is being dragged or animated to prevent extensions from messing things up
177 // while that's happening.
178 bool IsTabStripEditable() const;
180 // Returns false when there is a drag operation in progress so that the frame
182 bool IsTabStripCloseable() const;
184 // Updates the loading animations displayed by tabs in the tabstrip to the
186 void UpdateLoadingAnimations();
188 // Returns true if the specified point (in TabStrip coordinates) is in the
189 // window caption area of the browser window.
190 bool IsPositionInWindowCaption(const gfx::Point& point);
192 // Returns true if the specified rect (in TabStrip coordinates) intersects
193 // the window caption area of the browser window.
194 bool IsRectInWindowCaption(const gfx::Rect& rect);
196 // Set the background offset used by inactive tabs to match the frame image.
197 void SetBackgroundOffset(const gfx::Point& offset);
199 // Sets a painting style with miniature "tab indicator" rectangles at the top.
200 void SetImmersiveStyle(bool enable);
202 // Returns true if Tabs in this TabStrip are currently changing size or
204 bool IsAnimating() const;
206 // Stops any ongoing animations. If |layout| is true and an animation is
207 // ongoing this does a layout.
208 void StopAnimating(bool layout);
210 // Called to indicate whether the given URL is a supported file.
211 void FileSupported(const GURL& url, bool supported);
213 // TabController overrides:
214 const ui::ListSelectionModel& GetSelectionModel() override;
215 bool SupportsMultipleSelection() override;
216 void SelectTab(Tab* tab) override;
217 void ExtendSelectionTo(Tab* tab) override;
218 void ToggleSelected(Tab* tab) override;
219 void AddSelectionFromAnchorTo(Tab* tab) override;
220 void CloseTab(Tab* tab, CloseTabSource source) override;
221 void ToggleTabAudioMute(Tab* tab) override;
222 void ShowContextMenuForTab(Tab* tab,
224 ui::MenuSourceType source_type) override;
225 bool IsActiveTab(const Tab* tab) const override;
226 bool IsTabSelected(const Tab* tab) const override;
227 bool IsTabPinned(const Tab* tab) const override;
230 const ui::LocatedEvent& event,
231 const ui::ListSelectionModel& original_selection) override;
232 void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override;
233 bool EndDrag(EndDragReason reason) override;
234 Tab* GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) override;
235 void OnMouseEventInTab(views::View* source,
236 const ui::MouseEvent& event) override;
237 bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override;
238 bool IsImmersiveStyle() const override;
239 void UpdateTabAccessibilityState(const Tab* tab,
240 ui::AXViewState* state) override;
242 // MouseWatcherListener overrides:
243 void MouseMovedOutOfHost() override;
245 // views::View overrides:
246 void Layout() override;
247 void PaintChildren(gfx::Canvas* canvas,
248 const views::CullSet& cull_set) override;
249 const char* GetClassName() const override;
250 gfx::Size GetPreferredSize() const override;
251 // NOTE: the drag and drop methods are invoked from FrameView. This is done
252 // to allow for a drop region that extends outside the bounds of the TabStrip.
253 void OnDragEntered(const ui::DropTargetEvent& event) override;
254 int OnDragUpdated(const ui::DropTargetEvent& event) override;
255 void OnDragExited() override;
256 int OnPerformDrop(const ui::DropTargetEvent& event) override;
257 void GetAccessibleState(ui::AXViewState* state) override;
258 views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
260 // Returns preferred height in immersive style.
261 static int GetImmersiveHeight();
264 typedef std::vector<Tab*> Tabs;
265 typedef std::map<int, Tabs> TabsClosingMap;
266 typedef std::pair<TabsClosingMap::iterator,
267 Tabs::iterator> FindClosingTabResult;
269 class RemoveTabDelegate;
271 friend class TabDragController;
272 friend class TabDragControllerTest;
273 FRIEND_TEST_ALL_PREFIXES(TabDragControllerTest, GestureEndShouldEndDragTest);
274 friend class TabStripTest;
275 FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabHitTestMaskWhenStacked);
276 FRIEND_TEST_ALL_PREFIXES(TabStripTest, ClippedTabCloseButton);
278 // Used during a drop session of a url. Tracks the position of the drop as
279 // well as a window used to highlight where the drop occurs.
281 DropInfo(int drop_index,
284 views::Widget* context);
287 // Index of the tab to drop on. If drop_before is true, the drop should
288 // occur between the tab at drop_index - 1 and drop_index.
289 // WARNING: if drop_before is true it is possible this will == tab_count,
290 // which indicates the drop should create a new tab at the end of the tabs.
294 // Direction the arrow should point in. If true, the arrow is displayed
295 // above the tab and points down. If false, the arrow is displayed beneath
296 // the tab and points up.
299 // Renders the drop indicator.
300 views::Widget* arrow_window;
301 views::ImageView* arrow_view;
303 // The URL for the drop event.
306 // Whether the MIME type of the file pointed to by |url| is supported.
310 DISALLOW_COPY_AND_ASSIGN(DropInfo);
313 // Horizontal gap between mini and non-mini-tabs.
314 static const int kMiniToNonMiniGap;
318 // Creates and returns a new tab. The caller owners the returned tab.
321 // Invoked from |AddTabAt| after the newly created tab has been inserted.
322 void StartInsertTabAnimation(int model_index);
324 // Invoked from |MoveTab| after |tab_data_| has been updated to animate the
326 void StartMoveTabAnimation();
328 // Starts the remove tab animation.
329 void StartRemoveTabAnimation(int model_index);
331 // Schedules the animations and bounds changes necessary for a remove tab
333 void ScheduleRemoveTabAnimation(Tab* tab);
335 // Animates all the views to their ideal bounds.
336 // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds
337 // currently set in ideal_bounds.
338 void AnimateToIdealBounds();
340 // Returns whether the highlight button should be highlighted after a remove.
341 bool ShouldHighlightCloseButtonAfterRemove();
343 // Invoked from Layout if the size changes or layout is really needed.
346 // Sets the visibility state of all tabs based on ShouldTabBeVisible().
347 void SetTabVisibility();
349 // Drags the active tab by |delta|. |initial_positions| is the x-coordinates
350 // of the tabs when the drag started.
351 void DragActiveTab(const std::vector<int>& initial_positions, int delta);
353 // Sets the ideal bounds x-coordinates to |positions|.
354 void SetIdealBoundsFromPositions(const std::vector<int>& positions);
356 // Stacks the dragged tabs. This is used if the drag operation is
357 // MOVE_VISIBLE_TABS and the tabs don't fill the tabstrip. When this happens
358 // the active tab follows the mouse and the other tabs stack around it.
359 void StackDraggedTabs(int delta);
361 // Returns true if dragging has resulted in temporarily stacking the tabs.
362 bool IsStackingDraggedTabs() const;
364 // Invoked during drag to layout the tabs being dragged in |tabs| at
365 // |location|. If |initial_drag| is true, this is the initial layout after the
366 // user moved the mouse far enough to trigger a drag.
367 void LayoutDraggedTabsAt(const Tabs& tabs,
369 const gfx::Point& location,
372 // Calculates the bounds needed for each of the tabs, placing the result in
374 void CalculateBoundsForDraggedTabs(const Tabs& tabs,
375 std::vector<gfx::Rect>* bounds);
377 // Returns the size needed for the specified tabs. This is invoked during drag
378 // and drop to calculate offsets and positioning.
379 int GetSizeNeededForTabs(const Tabs& tabs);
381 // Returns the number of mini-tabs.
382 int GetMiniTabCount() const;
384 // Returns the last tab in the strip that's actually visible. This will be
385 // the actual last tab unless the strip is in the overflow state.
386 const Tab* GetLastVisibleTab() const;
388 // Adds the tab at |index| to |tabs_closing_map_| and removes the tab from
390 void RemoveTabFromViewModel(int index);
392 // Cleans up the Tab from the TabStrip. This is called from the tab animation
393 // code and is not a general-purpose method.
394 void RemoveAndDeleteTab(Tab* tab);
396 // Adjusts the indices of all tabs in |tabs_closing_map_| whose index is
397 // >= |index| to have a new index of |index + delta|.
398 void UpdateTabsClosingMap(int index, int delta);
400 // Used by TabDragController when the user starts or stops dragging tabs.
401 void StartedDraggingTabs(const Tabs& tabs);
403 // Invoked when TabDragController detaches a set of tabs.
404 void DraggedTabsDetached();
406 // Used by TabDragController when the user stops dragging tabs. |move_only| is
407 // true if the move behavior is TabDragController::MOVE_VISIBILE_TABS.
408 // |completed| is true if the drag operation completed successfully, false if
410 void StoppedDraggingTabs(const Tabs& tabs,
411 const std::vector<int>& initial_positions,
415 // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
416 // |is_first_tab| is set to true.
417 void StoppedDraggingTab(Tab* tab, bool* is_first_tab);
419 // Takes ownership of |controller|.
420 void OwnDragController(TabDragController* controller);
422 // Destroys the current TabDragController. This cancel the existing drag
424 void DestroyDragController();
426 // Releases ownership of the current TabDragController.
427 TabDragController* ReleaseDragController();
429 // Finds |tab| in the |tab_closing_map_| and returns a pair of iterators
430 // indicating precisely where it is.
431 FindClosingTabResult FindClosingTab(const Tab* tab);
433 // Paints all the tabs in |tabs_closing_map_[index]|.
434 void PaintClosingTabs(gfx::Canvas* canvas,
436 const views::CullSet& cull_set);
438 // Invoked when a mouse event occurs over |source|. Potentially switches the
439 // |stacked_layout_|.
440 void UpdateStackedLayoutFromMouseEvent(views::View* source,
441 const ui::MouseEvent& event);
443 // -- Tab Resize Layout -----------------------------------------------------
445 // Returns the exact (unrounded) current width of each tab.
446 void GetCurrentTabWidths(double* unselected_width,
447 double* selected_width) const;
449 // Returns the exact (unrounded) desired width of each tab, based on the
450 // desired strip width and number of tabs. If
451 // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in
452 // calculating the desired strip width; otherwise we use the current width.
453 // |mini_tab_count| gives the number of mini-tabs and |tab_count| the number
454 // of mini and non-mini-tabs.
455 void GetDesiredTabWidths(int tab_count,
457 double* unselected_width,
458 double* selected_width) const;
460 // Perform an animated resize-relayout of the TabStrip immediately.
461 void ResizeLayoutTabs();
463 // Invokes ResizeLayoutTabs() as long as we're not in a drag session. If we
464 // are in a drag session this restarts the timer.
465 void ResizeLayoutTabsFromTouch();
467 // Restarts |resize_layout_timer_|.
468 void StartResizeLayoutTabsFromTouchTimer();
470 // Sets the bounds of the tabs to |tab_bounds|.
471 void SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds);
473 // Ensure that the message loop observer used for event spying is added and
474 // removed appropriately so we can tell when to resize layout the tab strip.
475 void AddMessageLoopObserver();
476 void RemoveMessageLoopObserver();
478 // -- Link Drag & Drop ------------------------------------------------------
480 // Returns the bounds to render the drop at, in screen coordinates. Sets
481 // |is_beneath| to indicate whether the arrow is beneath the tab, or above
483 gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath);
485 // Updates the location of the drop based on the event.
486 void UpdateDropIndex(const ui::DropTargetEvent& event);
488 // Sets the location of the drop, repainting as necessary.
489 void SetDropIndex(int tab_data_index, bool drop_before);
491 // Returns the drop effect for dropping a URL on the tab strip. This does
492 // not query the data in anyway, it only looks at the source operations.
493 int GetDropEffect(const ui::DropTargetEvent& event);
495 // Returns the image to use for indicating a drop on a tab. If is_down is
496 // true, this returns an arrow pointing down.
497 static gfx::ImageSkia* GetDropArrowImage(bool is_down);
499 // -- Animations ------------------------------------------------------------
501 // Invoked prior to starting a new animation.
502 void PrepareForAnimation();
504 // Generates the ideal bounds for each of the tabs as well as the new tab
506 void GenerateIdealBounds();
508 // Generates the ideal bounds for the mini tabs. Returns the index to position
509 // the first non-mini tab and sets |first_non_mini_index| to the index of the
510 // first non-mini tab.
511 int GenerateIdealBoundsForMiniTabs(int* first_non_mini_index);
513 // Returns the width needed for the new tab button (and padding).
514 static int new_tab_button_width() {
515 return kNewTabButtonAssetWidth + kNewTabButtonHorizontalOffset;
518 // Returns the width of the area that contains tabs. This does not include
519 // the width of the new tab button.
520 int tab_area_width() const { return width() - new_tab_button_width(); }
522 // Starts various types of TabStrip animations.
523 void StartResizeLayoutAnimation();
524 void StartMiniTabAnimation();
525 void StartMouseInitiatedRemoveTabAnimation(int model_index);
527 // Returns true if the specified point in TabStrip coords is within the
528 // hit-test region of the specified Tab.
529 bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords);
531 // -- Touch Layout ----------------------------------------------------------
533 // Returns the position normal tabs start at.
534 int GetStartXForNormalTabs() const;
536 // Returns the tab to use for event handling. This uses FindTabForEventFrom()
537 // to do the actual searching.
538 Tab* FindTabForEvent(const gfx::Point& point);
540 // Returns the tab to use for event handling starting at index |start| and
541 // iterating by |delta|.
542 Tab* FindTabForEventFrom(const gfx::Point& point, int start, int delta);
544 // For a given point, finds a tab that is hit by the point. If the point hits
545 // an area on which two tabs are overlapping, the tab is selected as follows:
546 // - If one of the tabs is active, select it.
547 // - Select the left one.
548 // If no tabs are hit, returns NULL.
549 views::View* FindTabHitByPoint(const gfx::Point& point);
551 // Returns the x-coordinates of the tabs.
552 std::vector<int> GetTabXCoordinates();
554 // Creates/Destroys |touch_layout_| as necessary.
555 void SwapLayoutIfNecessary();
557 // Returns true if |touch_layout_| is needed.
558 bool NeedsTouchLayout() const;
560 // Sets the value of |reset_to_shrink_on_exit_|. If true |mouse_watcher_| is
561 // used to track when the mouse truly exits the tabstrip and the stacked
563 void SetResetToShrinkOnExit(bool value);
565 // views::ButtonListener implementation:
566 void ButtonPressed(views::Button* sender, const ui::Event& event) override;
569 const views::View* GetViewByID(int id) const override;
570 bool OnMousePressed(const ui::MouseEvent& event) override;
571 bool OnMouseDragged(const ui::MouseEvent& event) override;
572 void OnMouseReleased(const ui::MouseEvent& event) override;
573 void OnMouseCaptureLost() override;
574 void OnMouseMoved(const ui::MouseEvent& event) override;
575 void OnMouseEntered(const ui::MouseEvent& event) override;
577 // ui::EventHandler overrides.
578 void OnGestureEvent(ui::GestureEvent* event) override;
580 // views::ViewTargeterDelegate:
581 views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
583 // -- Member Variables ------------------------------------------------------
585 // There is a one-to-one mapping between each of the tabs in the
586 // TabStripController (TabStripModel) and |tabs_|. Because we animate tab
587 // removal there exists a period of time where a tab is displayed but not in
588 // the model. When this occurs the tab is removed from |tabs_| and placed in
589 // |tabs_closing_map_|. When the animation completes the tab is removed from
590 // |tabs_closing_map_|. The painting code ensures both sets of tabs are
591 // painted, and the event handling code ensures only tabs in |tabs_| are used.
592 views::ViewModelT<Tab> tabs_;
593 TabsClosingMap tabs_closing_map_;
595 scoped_ptr<TabStripController> controller_;
597 // The "New Tab" button.
598 NewTabButton* newtab_button_;
600 // Ideal bounds of the new tab button.
601 gfx::Rect newtab_button_bounds_;
603 // The current widths of various types of tabs. We save these so that, as
604 // users close tabs while we're holding them at the same size, we can lay out
605 // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving
606 // them all at their existing, rounded widths.
607 double current_unselected_width_;
608 double current_selected_width_;
610 // If this value is nonnegative, it is used in GetDesiredTabWidths() to
611 // calculate how much space in the tab strip to use for tabs. Most of the
612 // time this will be -1, but while we're handling closing a tab via the mouse,
613 // we'll set this to the edge of the last tab before closing, so that if we
614 // are closing the last tab and need to resize immediately, we'll resize only
615 // back to this width, thus once again placing the last tab under the mouse
617 int available_width_for_tabs_;
619 // True if PrepareForCloseAt has been invoked. When true remove animations
620 // preserve current tab bounds.
623 // Valid for the lifetime of a drag over us.
624 scoped_ptr<DropInfo> drop_info_;
626 // To ensure all tabs pulse at the same time they share the same animation
627 // container. This is that animation container.
628 scoped_refptr<gfx::AnimationContainer> animation_container_;
630 // MouseWatcher is used for two things:
631 // . When a tab is closed to reset the layout.
632 // . When a mouse is used and the layout dynamically adjusts and is currently
633 // stacked (|stacked_layout_| is true).
634 scoped_ptr<views::MouseWatcher> mouse_watcher_;
636 // The controller for a drag initiated from a Tab. Valid for the lifetime of
638 scoped_ptr<TabDragController> drag_controller_;
640 views::BoundsAnimator bounds_animator_;
642 // Size we last layed out at.
643 gfx::Size last_layout_size_;
645 // See description above stacked_layout().
646 bool stacked_layout_;
648 // Should the layout dynamically adjust?
651 // Only used while in touch mode.
652 scoped_ptr<StackedTabStripLayout> touch_layout_;
654 // If true the |stacked_layout_| is set to false when the mouse exits the
655 // tabstrip (as determined using MouseWatcher).
656 bool reset_to_shrink_on_exit_;
658 // Location of the mouse at the time of the last move.
659 gfx::Point last_mouse_move_location_;
661 // Time of the last mouse move event.
662 base::TimeTicks last_mouse_move_time_;
664 // Number of mouse moves.
665 int mouse_move_count_;
667 // Timer used when a tab is closed and we need to relayout. Only used when a
668 // tab close comes from a touch device.
669 base::OneShotTimer<TabStrip> resize_layout_timer_;
671 // True if tabs are painted as rectangular light-bars.
672 bool immersive_style_;
675 typedef ObserverList<TabStripObserver> TabStripObservers;
676 TabStripObservers observers_;
678 DISALLOW_COPY_AND_ASSIGN(TabStrip);
681 #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_