tab_strip.h revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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.
4
5#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
6#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
7
8#include <vector>
9
10#include "base/compiler_specific.h"
11#include "base/memory/ref_counted.h"
12#include "base/timer.h"
13#include "chrome/browser/ui/tabs/tab_strip_layout_type.h"
14#include "chrome/browser/ui/views/tabs/tab.h"
15#include "chrome/browser/ui/views/tabs/tab_controller.h"
16#include "ui/base/animation/animation_container.h"
17#include "ui/gfx/point.h"
18#include "ui/gfx/rect.h"
19#include "ui/views/animation/bounds_animator.h"
20#include "ui/views/controls/button/image_button.h"
21#include "ui/views/mouse_watcher.h"
22#include "ui/views/view.h"
23#include "ui/views/view_model.h"
24
25class NewTabButton;
26class StackedTabStripLayout;
27class Tab;
28class TabDragController;
29class TabStripController;
30class TabStripObserver;
31
32namespace ui {
33class ListSelectionModel;
34}
35
36namespace views {
37class ImageView;
38}
39
40///////////////////////////////////////////////////////////////////////////////
41//
42// TabStrip
43//
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.
51//
52///////////////////////////////////////////////////////////////////////////////
53class TabStrip : public views::View,
54                 public views::ButtonListener,
55                 public views::MouseWatcherListener,
56                 public TabController {
57 public:
58  static const char kViewClassName[];
59
60  explicit TabStrip(TabStripController* controller);
61  virtual ~TabStrip();
62
63  // Add and remove observers to changes within this TabStrip.
64  void AddObserver(TabStripObserver* observer);
65  void RemoveObserver(TabStripObserver* observer);
66
67  // Sets the layout type. If |adjust_layout| is true the layout type changes
68  // based on whether the user uses a mouse or touch device with the tabstrip.
69  // If |adjust_layout| is false the layout is fixed to |layout_type|.
70  void SetLayoutType(TabStripLayoutType layout_type, bool adjust_layout);
71  TabStripLayoutType layout_type() const { return layout_type_; }
72
73  // Returns the bounds of the new tab button.
74  gfx::Rect GetNewTabButtonBounds();
75
76  // Returns true if the new tab button should be sized to the top of the tab
77  // strip.
78  bool SizeTabButtonToTopOfTabStrip();
79
80  // Starts highlighting the tab at the specified index.
81  void StartHighlight(int model_index);
82
83  // Stops all tab higlighting.
84  void StopAllHighlighting();
85
86  // Adds a tab at the specified index.
87  void AddTabAt(int model_index, const TabRendererData& data, bool is_active);
88
89  // Moves a tab.
90  void MoveTab(int from_model_index,
91               int to_model_index,
92               const TabRendererData& data);
93
94  // Removes a tab at the specified index.
95  void RemoveTabAt(int model_index);
96
97  // Sets the tab data at the specified model index.
98  void SetTabData(int model_index, const TabRendererData& data);
99
100  // Invoked from the controller when the close initiates from the TabController
101  // (the user clicked the tab close button or middle clicked the tab). This is
102  // invoked from Close. Because of unload handlers Close is not always
103  // immediately followed by RemoveTabAt.
104  void PrepareForCloseAt(int model_index, CloseTabSource source);
105
106  // Invoked when the selection changes from |old_selection| to
107  // |new_selection|.
108  void SetSelection(const ui::ListSelectionModel& old_selection,
109                    const ui::ListSelectionModel& new_selection);
110
111  // Invoked when the title of a tab changes and the tab isn't loading.
112  void TabTitleChangedNotLoading(int model_index);
113
114  // Retrieves the ideal bounds for the Tab at the specified index.
115  const gfx::Rect& ideal_bounds(int tab_data_index) {
116    return tabs_.ideal_bounds(tab_data_index);
117  }
118
119  // Returns the Tab at |index|.
120  Tab* tab_at(int index) const;
121
122  // Returns the index of the specified tab in the model coordinate system, or
123  // -1 if tab is closing or not valid.
124  int GetModelIndexOfTab(const Tab* tab) const;
125
126  // Gets the number of Tabs in the tab strip.
127  int tab_count() const { return tabs_.view_size(); }
128
129  // Cover method for TabStripController::GetCount.
130  int GetModelCount() const;
131
132  // Cover method for TabStripController::IsValidIndex.
133  bool IsValidModelIndex(int model_index) const;
134
135  TabStripController* controller() const { return controller_.get(); }
136
137  // Creates and returns a tab that can be used for dragging. Ownership passes
138  // to the caller.
139  Tab* CreateTabForDragging();
140
141  // Returns true if a drag session is currently active.
142  bool IsDragSessionActive() const;
143
144  // Returns true if a tab is being dragged into this tab strip.
145  bool IsActiveDropTarget() const;
146
147  // Returns true if the tab strip is editable. Returns false if the tab strip
148  // is being dragged or animated to prevent extensions from messing things up
149  // while that's happening.
150  bool IsTabStripEditable() const;
151
152  // Returns false when there is a drag operation in progress so that the frame
153  // doesn't close.
154  bool IsTabStripCloseable() const;
155
156  // Updates the loading animations displayed by tabs in the tabstrip to the
157  // next frame.
158  void UpdateLoadingAnimations();
159
160  // Returns true if the specified point (in TabStrip coordinates) is in the
161  // window caption area of the browser window.
162  bool IsPositionInWindowCaption(const gfx::Point& point);
163
164  // Set the background offset used by inactive tabs to match the frame image.
165  void SetBackgroundOffset(const gfx::Point& offset);
166
167  // Returns the new tab button. This is never NULL.
168  views::View* newtab_button();
169
170  // Sets a painting style with miniature "tab indicator" rectangles at the top.
171  void SetImmersiveStyle(bool enable);
172
173  // Returns true if Tabs in this TabStrip are currently changing size or
174  // position.
175  bool IsAnimating() const;
176
177  // Stops any ongoing animations. If |layout| is true and an animation is
178  // ongoing this does a layout.
179  void StopAnimating(bool layout);
180
181  // TabController overrides:
182  virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE;
183  virtual bool SupportsMultipleSelection() OVERRIDE;
184  virtual void SelectTab(Tab* tab) OVERRIDE;
185  virtual void ExtendSelectionTo(Tab* tab) OVERRIDE;
186  virtual void ToggleSelected(Tab* tab) OVERRIDE;
187  virtual void AddSelectionFromAnchorTo(Tab* tab) OVERRIDE;
188  virtual void CloseTab(Tab* tab, CloseTabSource source) OVERRIDE;
189  virtual void ShowContextMenuForTab(Tab* tab,
190                                     const gfx::Point& p,
191                                     ui::MenuSourceType source_type) OVERRIDE;
192  virtual bool IsActiveTab(const Tab* tab) const OVERRIDE;
193  virtual bool IsTabSelected(const Tab* tab) const OVERRIDE;
194  virtual bool IsTabPinned(const Tab* tab) const OVERRIDE;
195  virtual void MaybeStartDrag(
196      Tab* tab,
197      const ui::LocatedEvent& event,
198      const ui::ListSelectionModel& original_selection) OVERRIDE;
199  virtual void ContinueDrag(views::View* view,
200                            const ui::LocatedEvent& event) OVERRIDE;
201  virtual bool EndDrag(EndDragReason reason) OVERRIDE;
202  virtual Tab* GetTabAt(Tab* tab,
203                            const gfx::Point& tab_in_tab_coordinates) OVERRIDE;
204  virtual void OnMouseEventInTab(views::View* source,
205                                 const ui::MouseEvent& event) OVERRIDE;
206  virtual bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) OVERRIDE;
207  virtual bool IsImmersiveStyle() const OVERRIDE;
208
209  // MouseWatcherListener overrides:
210  virtual void MouseMovedOutOfHost() OVERRIDE;
211
212  // views::View overrides:
213  virtual void Layout() OVERRIDE;
214  virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
215  virtual const char* GetClassName() const OVERRIDE;
216  virtual gfx::Size GetPreferredSize() OVERRIDE;
217  // NOTE: the drag and drop methods are invoked from FrameView. This is done
218  // to allow for a drop region that extends outside the bounds of the TabStrip.
219  virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
220  virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
221  virtual void OnDragExited() OVERRIDE;
222  virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
223  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
224  virtual views::View* GetEventHandlerForPoint(
225      const gfx::Point& point) OVERRIDE;
226  virtual views::View* GetTooltipHandlerForPoint(
227      const gfx::Point& point) OVERRIDE;
228
229  // Returns preferred height in immersive style.
230  static int GetImmersiveHeight();
231
232 protected:
233  // Horizontal gap between mini and non-mini-tabs.
234  static const int kMiniToNonMiniGap;
235
236  void set_ideal_bounds(int index, const gfx::Rect& bounds) {
237    tabs_.set_ideal_bounds(index, bounds);
238  }
239
240  // Returns the number of mini-tabs.
241  int GetMiniTabCount() const;
242
243  // views::ButtonListener implementation:
244  virtual void ButtonPressed(views::Button* sender,
245                             const ui::Event& event) OVERRIDE;
246
247  // View overrides.
248  virtual const views::View* GetViewByID(int id) const OVERRIDE;
249  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
250  virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
251  virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
252  virtual void OnMouseCaptureLost() OVERRIDE;
253  virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE;
254  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
255
256  // ui::EventHandler overrides.
257  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
258
259 private:
260  typedef std::map<int, std::vector<Tab*> > TabsClosingMap;
261
262  class RemoveTabDelegate;
263
264  friend class TabDragController;
265  friend class TabDragControllerTest;
266
267  // Used during a drop session of a url. Tracks the position of the drop as
268  // well as a window used to highlight where the drop occurs.
269  struct DropInfo {
270    DropInfo(int drop_index,
271             bool drop_before,
272             bool point_down,
273             views::Widget* context);
274    ~DropInfo();
275
276    // Index of the tab to drop on. If drop_before is true, the drop should
277    // occur between the tab at drop_index - 1 and drop_index.
278    // WARNING: if drop_before is true it is possible this will == tab_count,
279    // which indicates the drop should create a new tab at the end of the tabs.
280    int drop_index;
281    bool drop_before;
282
283    // Direction the arrow should point in. If true, the arrow is displayed
284    // above the tab and points down. If false, the arrow is displayed beneath
285    // the tab and points up.
286    bool point_down;
287
288    // Renders the drop indicator.
289    views::Widget* arrow_window;
290    views::ImageView* arrow_view;
291
292   private:
293    DISALLOW_COPY_AND_ASSIGN(DropInfo);
294  };
295
296  void Init();
297
298  // Creates and returns a new tab. The caller owners the returned tab.
299  Tab* CreateTab();
300
301  // Invoked from |AddTabAt| after the newly created tab has been inserted.
302  void StartInsertTabAnimation(int model_index);
303
304  // Invoked from |MoveTab| after |tab_data_| has been updated to animate the
305  // move.
306  void StartMoveTabAnimation();
307
308  // Starts the remove tab animation.
309  void StartRemoveTabAnimation(int model_index);
310
311  // Schedules the animations and bounds changes necessary for a remove tab
312  // animation.
313  void ScheduleRemoveTabAnimation(Tab* tab);
314
315  // Animates all the views to their ideal bounds.
316  // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds
317  // currently set in ideal_bounds.
318  void AnimateToIdealBounds();
319
320  // Returns whether the highlight button should be highlighted after a remove.
321  bool ShouldHighlightCloseButtonAfterRemove();
322
323  // Invoked from Layout if the size changes or layout is really needed.
324  void DoLayout();
325
326  // Drags the active tab by |delta|. |initial_positions| is the x-coordinates
327  // of the tabs when the drag started.
328  void DragActiveTab(const std::vector<int>& initial_positions, int delta);
329
330  // Sets the ideal bounds x-coordinates to |positions|.
331  void SetIdealBoundsFromPositions(const std::vector<int>& positions);
332
333  // Stacks the dragged tabs. This is used if the drag operation is
334  // MOVE_VISIBILE_TABS and the tabs don't fill the tabstrip. When this happens
335  // the active tab follows the mouse and the other tabs stack around it.
336  void StackDraggedTabs(int delta);
337
338  // Returns true if dragging has resulted in temporarily stacking the tabs.
339  bool IsStackingDraggedTabs() const;
340
341  // Invoked during drag to layout the tabs being dragged in |tabs| at
342  // |location|. If |initial_drag| is true, this is the initial layout after the
343  // user moved the mouse far enough to trigger a drag.
344  void LayoutDraggedTabsAt(const std::vector<Tab*>& tabs,
345                           Tab* active_tab,
346                           const gfx::Point& location,
347                           bool initial_drag);
348
349  // Calculates the bounds needed for each of the tabs, placing the result in
350  // |bounds|.
351  void CalculateBoundsForDraggedTabs(const std::vector<Tab*>& tabs,
352                                     std::vector<gfx::Rect>* bounds);
353
354  // Returns the size needed for the specified tabs. This is invoked during drag
355  // and drop to calculate offsets and positioning.
356  int GetSizeNeededForTabs(const std::vector<Tab*>& tabs);
357
358  // Adds the tab at |index| to |tabs_closing_map_| and removes the tab from
359  // |tabs_|.
360  void RemoveTabFromViewModel(int index);
361
362  // Cleans up the Tab from the TabStrip. This is called from the tab animation
363  // code and is not a general-purpose method.
364  void RemoveAndDeleteTab(Tab* tab);
365
366  // Adjusts the indices of all tabs in |tabs_closing_map_| whose index is
367  // >= |index| to have a new index of |index + delta|.
368  void UpdateTabsClosingMap(int index, int delta);
369
370  // Used by TabDragController when the user starts or stops dragging tabs.
371  void StartedDraggingTabs(const std::vector<Tab*>& tabs);
372
373  // Invoked when TabDragController detaches a set of tabs.
374  void DraggedTabsDetached();
375
376  // Used by TabDragController when the user stops dragging tabs. |move_only| is
377  // true if the move behavior is TabDragController::MOVE_VISIBILE_TABS.
378  // |completed| is true if the drag operation completed successfully, false if
379  // it was reverted.
380  void StoppedDraggingTabs(const std::vector<Tab*>& tabs,
381                           const std::vector<int>& initial_positions,
382                           bool move_only,
383                           bool completed);
384
385  // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
386  // |is_first_tab| is set to true.
387  void StoppedDraggingTab(Tab* tab, bool* is_first_tab);
388
389  // Takes ownership of |controller|.
390  void OwnDragController(TabDragController* controller);
391
392  // Destroys the current TabDragController. This cancel the existing drag
393  // operation.
394  void DestroyDragController();
395
396  // Releases ownership of the current TabDragController.
397  TabDragController* ReleaseDragController();
398
399  // Paints all the tabs in |tabs_closing_map_[index]|.
400  void PaintClosingTabs(gfx::Canvas* canvas, int index);
401
402  // Invoked when a mouse event occurs over |source|. Potentially switches the
403  // layout type.
404  void UpdateLayoutTypeFromMouseEvent(views::View* source,
405                                      const ui::MouseEvent& event);
406
407  // -- Tab Resize Layout -----------------------------------------------------
408
409  // Returns the exact (unrounded) current width of each tab.
410  void GetCurrentTabWidths(double* unselected_width,
411                           double* selected_width) const;
412
413  // Returns the exact (unrounded) desired width of each tab, based on the
414  // desired strip width and number of tabs.  If
415  // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in
416  // calculating the desired strip width; otherwise we use the current width.
417  // |mini_tab_count| gives the number of mini-tabs and |tab_count| the number
418  // of mini and non-mini-tabs.
419  void GetDesiredTabWidths(int tab_count,
420                           int mini_tab_count,
421                           double* unselected_width,
422                           double* selected_width) const;
423
424  // Perform an animated resize-relayout of the TabStrip immediately.
425  void ResizeLayoutTabs();
426
427  // Invokes ResizeLayoutTabs() as long as we're not in a drag session. If we
428  // are in a drag session this restarts the timer.
429  void ResizeLayoutTabsFromTouch();
430
431  // Restarts |resize_layout_timer_|.
432  void StartResizeLayoutTabsFromTouchTimer();
433
434  // Sets the bounds of the tabs to |tab_bounds|.
435  void SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds);
436
437  // Ensure that the message loop observer used for event spying is added and
438  // removed appropriately so we can tell when to resize layout the tab strip.
439  void AddMessageLoopObserver();
440  void RemoveMessageLoopObserver();
441
442  // -- Link Drag & Drop ------------------------------------------------------
443
444  // Returns the bounds to render the drop at, in screen coordinates. Sets
445  // |is_beneath| to indicate whether the arrow is beneath the tab, or above
446  // it.
447  gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath);
448
449  // Updates the location of the drop based on the event.
450  void UpdateDropIndex(const ui::DropTargetEvent& event);
451
452  // Sets the location of the drop, repainting as necessary.
453  void SetDropIndex(int tab_data_index, bool drop_before);
454
455  // Returns the drop effect for dropping a URL on the tab strip. This does
456  // not query the data in anyway, it only looks at the source operations.
457  int GetDropEffect(const ui::DropTargetEvent& event);
458
459  // Returns the image to use for indicating a drop on a tab. If is_down is
460  // true, this returns an arrow pointing down.
461  static gfx::ImageSkia* GetDropArrowImage(bool is_down);
462
463  // -- Animations ------------------------------------------------------------
464
465  // Invoked prior to starting a new animation.
466  void PrepareForAnimation();
467
468  // Generates the ideal bounds for each of the tabs as well as the new tab
469  // button.
470  void GenerateIdealBounds();
471
472  // Generates the ideal bounds for the mini tabs. Returns the index to position
473  // the first non-mini tab and sets |first_non_mini_index| to the index of the
474  // first non-mini tab.
475  int GenerateIdealBoundsForMiniTabs(int* first_non_mini_index);
476
477  // Returns the width needed for the new tab button (and padding).
478  int new_tab_button_width() const;
479
480  // Starts various types of TabStrip animations.
481  void StartResizeLayoutAnimation();
482  void StartMiniTabAnimation();
483  void StartMouseInitiatedRemoveTabAnimation(int model_index);
484
485  // Returns true if the specified point in TabStrip coords is within the
486  // hit-test region of the specified Tab.
487  bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords);
488
489  // -- Touch Layout ----------------------------------------------------------
490
491  // Returns the position normal tabs start at.
492  int GetStartXForNormalTabs() const;
493
494  // Returns the tab to use for event handling. This uses FindTabForEventFrom()
495  // to do the actual searching.
496  Tab* FindTabForEvent(const gfx::Point& point);
497
498  // Returns the tab to use for event handling starting at index |start| and
499  // iterating by |delta|.
500  Tab* FindTabForEventFrom(const gfx::Point& point, int start, int delta);
501
502  // For a given point, finds a tab that is hit by the point. If the point hits
503  // an area on which two tabs are overlapping, the tab is selected as follows:
504  // - If one of the tabs is active, select it.
505  // - Select the left one.
506  // If no tabs are hit, returns NULL.
507  views::View* FindTabHitByPoint(const gfx::Point& point);
508
509  // Returns the x-coordinates of the tabs.
510  std::vector<int> GetTabXCoordinates();
511
512  // Creates/Destroys |touch_layout_| as necessary.
513  void SwapLayoutIfNecessary();
514
515  // Returns true if |touch_layout_| is needed.
516  bool NeedsTouchLayout() const;
517
518  // Sets the value of |reset_to_shrink_on_exit_|. If true |mouse_watcher_| is
519  // used to track when the mouse truly exits the tabstrip and the layout type
520  // is reset.
521  void SetResetToShrinkOnExit(bool value);
522
523  // Should the layout dynamically adjust?
524  bool GetAdjustLayout() const;
525
526  // -- Member Variables ------------------------------------------------------
527
528  // There is a one-to-one mapping between each of the tabs in the
529  // TabStripController (TabStripModel) and |tabs_|. Because we animate tab
530  // removal there exists a period of time where a tab is displayed but not in
531  // the model. When this occurs the tab is removed from |tabs_| and placed in
532  // |tabs_closing_map_|. When the animation completes the tab is removed from
533  // |tabs_closing_map_|. The painting code ensures both sets of tabs are
534  // painted, and the event handling code ensures only tabs in |tabs_| are used.
535  views::ViewModel tabs_;
536  TabsClosingMap tabs_closing_map_;
537
538  scoped_ptr<TabStripController> controller_;
539
540  // The "New Tab" button.
541  NewTabButton* newtab_button_;
542
543  // Ideal bounds of the new tab button.
544  gfx::Rect newtab_button_bounds_;
545
546  // The current widths of various types of tabs.  We save these so that, as
547  // users close tabs while we're holding them at the same size, we can lay out
548  // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving
549  // them all at their existing, rounded widths.
550  double current_unselected_width_;
551  double current_selected_width_;
552
553  // If this value is nonnegative, it is used in GetDesiredTabWidths() to
554  // calculate how much space in the tab strip to use for tabs.  Most of the
555  // time this will be -1, but while we're handling closing a tab via the mouse,
556  // we'll set this to the edge of the last tab before closing, so that if we
557  // are closing the last tab and need to resize immediately, we'll resize only
558  // back to this width, thus once again placing the last tab under the mouse
559  // cursor.
560  int available_width_for_tabs_;
561
562  // True if PrepareForCloseAt has been invoked. When true remove animations
563  // preserve current tab bounds.
564  bool in_tab_close_;
565
566  // Valid for the lifetime of a drag over us.
567  scoped_ptr<DropInfo> drop_info_;
568
569  // To ensure all tabs pulse at the same time they share the same animation
570  // container. This is that animation container.
571  scoped_refptr<ui::AnimationContainer> animation_container_;
572
573  // MouseWatcher is used for two things:
574  // . When a tab is closed to reset the layout.
575  // . When a mouse is used and the layout dynamically adjusts and is currently
576  //   TAB_STRIP_LAYOUT_STACKED.
577  scoped_ptr<views::MouseWatcher> mouse_watcher_;
578
579  // The controller for a drag initiated from a Tab. Valid for the lifetime of
580  // the drag session.
581  scoped_ptr<TabDragController> drag_controller_;
582
583  views::BoundsAnimator bounds_animator_;
584
585  // Size we last layed out at.
586  gfx::Size last_layout_size_;
587
588  TabStripLayoutType layout_type_;
589
590  // See description above SetLayoutType().
591  bool adjust_layout_;
592
593  // Only used while in touch mode.
594  scoped_ptr<StackedTabStripLayout> touch_layout_;
595
596  // If true the layout type is set to TAB_STRIP_LAYOUT_SHRINK when the mouse
597  // exits the tabstrip (as determined using MouseWatcher).
598  bool reset_to_shrink_on_exit_;
599
600  // Location of the mouse at the time of the last move.
601  gfx::Point last_mouse_move_location_;
602
603  // Time of the last mouse move event.
604  base::TimeTicks last_mouse_move_time_;
605
606  // Number of mouse moves.
607  int mouse_move_count_;
608
609  // Timer used when a tab is closed and we need to relayout. Only used when a
610  // tab close comes from a touch device.
611  base::OneShotTimer<TabStrip> resize_layout_timer_;
612
613  // True if tabs are painted as rectangular light-bars.
614  bool immersive_style_;
615
616  // Our observers.
617  typedef ObserverList<TabStripObserver> TabStripObservers;
618  TabStripObservers observers_;
619
620  DISALLOW_COPY_AND_ASSIGN(TabStrip);
621};
622
623#endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
624