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/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/gfx/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"
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 TabController
{
58 static const char kViewClassName
[];
60 explicit TabStrip(TabStripController
* controller
);
63 // Add and remove observers to changes within this TabStrip.
64 void AddObserver(TabStripObserver
* observer
);
65 void RemoveObserver(TabStripObserver
* observer
);
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_
; }
73 // Returns the bounds of the new tab button.
74 gfx::Rect
GetNewTabButtonBounds();
76 // Returns true if the new tab button should be sized to the top of the tab
78 bool SizeTabButtonToTopOfTabStrip();
80 // Starts highlighting the tab at the specified index.
81 void StartHighlight(int model_index
);
83 // Stops all tab higlighting.
84 void StopAllHighlighting();
86 // Adds a tab at the specified index.
87 void AddTabAt(int model_index
, const TabRendererData
& data
, bool is_active
);
90 void MoveTab(int from_model_index
,
92 const TabRendererData
& data
);
94 // Removes a tab at the specified index.
95 void RemoveTabAt(int model_index
);
97 // Sets the tab data at the specified model index.
98 void SetTabData(int model_index
, const TabRendererData
& data
);
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
);
106 // Invoked when the selection changes from |old_selection| to
108 void SetSelection(const ui::ListSelectionModel
& old_selection
,
109 const ui::ListSelectionModel
& new_selection
);
111 // Invoked when the title of a tab changes and the tab isn't loading.
112 void TabTitleChangedNotLoading(int model_index
);
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
);
119 // Returns the Tab at |index|.
120 Tab
* tab_at(int index
) const;
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;
126 // Gets the number of Tabs in the tab strip.
127 int tab_count() const { return tabs_
.view_size(); }
129 // Cover method for TabStripController::GetCount.
130 int GetModelCount() const;
132 // Cover method for TabStripController::IsValidIndex.
133 bool IsValidModelIndex(int model_index
) const;
135 TabStripController
* controller() const { return controller_
.get(); }
137 // Creates and returns a tab that can be used for dragging. Ownership passes
139 Tab
* CreateTabForDragging();
141 // Returns true if a drag session is currently active.
142 bool IsDragSessionActive() const;
144 // Returns true if a tab is being dragged into this tab strip.
145 bool IsActiveDropTarget() const;
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;
152 // Returns false when there is a drag operation in progress so that the frame
154 bool IsTabStripCloseable() const;
156 // Updates the loading animations displayed by tabs in the tabstrip to the
158 void UpdateLoadingAnimations();
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
);
164 // Returns true if the specified rect (in TabStrip coordinates) intersects
165 // the window caption area of the browser window.
166 bool IsRectInWindowCaption(const gfx::Rect
& rect
);
168 // Set the background offset used by inactive tabs to match the frame image.
169 void SetBackgroundOffset(const gfx::Point
& offset
);
171 // Returns the new tab button. This is never NULL.
172 views::View
* newtab_button();
174 // Sets a painting style with miniature "tab indicator" rectangles at the top.
175 void SetImmersiveStyle(bool enable
);
177 // Returns true if Tabs in this TabStrip are currently changing size or
179 bool IsAnimating() const;
181 // Stops any ongoing animations. If |layout| is true and an animation is
182 // ongoing this does a layout.
183 void StopAnimating(bool layout
);
185 // Called to indicate whether the given URL is a supported file.
186 void FileSupported(const GURL
& url
, bool supported
);
188 // TabController overrides:
189 virtual const ui::ListSelectionModel
& GetSelectionModel() OVERRIDE
;
190 virtual bool SupportsMultipleSelection() OVERRIDE
;
191 virtual void SelectTab(Tab
* tab
) OVERRIDE
;
192 virtual void ExtendSelectionTo(Tab
* tab
) OVERRIDE
;
193 virtual void ToggleSelected(Tab
* tab
) OVERRIDE
;
194 virtual void AddSelectionFromAnchorTo(Tab
* tab
) OVERRIDE
;
195 virtual void CloseTab(Tab
* tab
, CloseTabSource source
) OVERRIDE
;
196 virtual void ShowContextMenuForTab(Tab
* tab
,
198 ui::MenuSourceType source_type
) OVERRIDE
;
199 virtual bool IsActiveTab(const Tab
* tab
) const OVERRIDE
;
200 virtual bool IsTabSelected(const Tab
* tab
) const OVERRIDE
;
201 virtual bool IsTabPinned(const Tab
* tab
) const OVERRIDE
;
202 virtual void MaybeStartDrag(
204 const ui::LocatedEvent
& event
,
205 const ui::ListSelectionModel
& original_selection
) OVERRIDE
;
206 virtual void ContinueDrag(views::View
* view
,
207 const ui::LocatedEvent
& event
) OVERRIDE
;
208 virtual bool EndDrag(EndDragReason reason
) OVERRIDE
;
209 virtual Tab
* GetTabAt(Tab
* tab
,
210 const gfx::Point
& tab_in_tab_coordinates
) OVERRIDE
;
211 virtual void OnMouseEventInTab(views::View
* source
,
212 const ui::MouseEvent
& event
) OVERRIDE
;
213 virtual bool ShouldPaintTab(const Tab
* tab
, gfx::Rect
* clip
) OVERRIDE
;
214 virtual bool IsImmersiveStyle() const OVERRIDE
;
216 // MouseWatcherListener overrides:
217 virtual void MouseMovedOutOfHost() OVERRIDE
;
219 // views::View overrides:
220 virtual void Layout() OVERRIDE
;
221 virtual void PaintChildren(gfx::Canvas
* canvas
) OVERRIDE
;
222 virtual const char* GetClassName() const OVERRIDE
;
223 virtual gfx::Size
GetPreferredSize() OVERRIDE
;
224 // NOTE: the drag and drop methods are invoked from FrameView. This is done
225 // to allow for a drop region that extends outside the bounds of the TabStrip.
226 virtual void OnDragEntered(const ui::DropTargetEvent
& event
) OVERRIDE
;
227 virtual int OnDragUpdated(const ui::DropTargetEvent
& event
) OVERRIDE
;
228 virtual void OnDragExited() OVERRIDE
;
229 virtual int OnPerformDrop(const ui::DropTargetEvent
& event
) OVERRIDE
;
230 virtual void GetAccessibleState(ui::AccessibleViewState
* state
) OVERRIDE
;
231 virtual views::View
* GetEventHandlerForRect(const gfx::Rect
& rect
) OVERRIDE
;
232 virtual views::View
* GetTooltipHandlerForPoint(
233 const gfx::Point
& point
) OVERRIDE
;
235 // Returns preferred height in immersive style.
236 static int GetImmersiveHeight();
239 // Horizontal gap between mini and non-mini-tabs.
240 static const int kMiniToNonMiniGap
;
242 void set_ideal_bounds(int index
, const gfx::Rect
& bounds
) {
243 tabs_
.set_ideal_bounds(index
, bounds
);
246 // Returns the number of mini-tabs.
247 int GetMiniTabCount() const;
249 // views::ButtonListener implementation:
250 virtual void ButtonPressed(views::Button
* sender
,
251 const ui::Event
& event
) OVERRIDE
;
254 virtual const views::View
* GetViewByID(int id
) const OVERRIDE
;
255 virtual bool OnMousePressed(const ui::MouseEvent
& event
) OVERRIDE
;
256 virtual bool OnMouseDragged(const ui::MouseEvent
& event
) OVERRIDE
;
257 virtual void OnMouseReleased(const ui::MouseEvent
& event
) OVERRIDE
;
258 virtual void OnMouseCaptureLost() OVERRIDE
;
259 virtual void OnMouseMoved(const ui::MouseEvent
& event
) OVERRIDE
;
260 virtual void OnMouseEntered(const ui::MouseEvent
& event
) OVERRIDE
;
262 // ui::EventHandler overrides.
263 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
;
266 typedef std::map
<int, std::vector
<Tab
*> > TabsClosingMap
;
268 class RemoveTabDelegate
;
270 friend class TabDragController
;
271 friend class TabDragControllerTest
;
272 FRIEND_TEST_ALL_PREFIXES(TabDragControllerTest
, GestureEndShouldEndDragTest
);
273 friend class TabStripTest
;
274 FRIEND_TEST_ALL_PREFIXES(TabStripTest
, TabHitTestMaskWhenStacked
);
276 // Used during a drop session of a url. Tracks the position of the drop as
277 // well as a window used to highlight where the drop occurs.
279 DropInfo(int drop_index
,
282 views::Widget
* context
);
285 // Index of the tab to drop on. If drop_before is true, the drop should
286 // occur between the tab at drop_index - 1 and drop_index.
287 // WARNING: if drop_before is true it is possible this will == tab_count,
288 // which indicates the drop should create a new tab at the end of the tabs.
292 // Direction the arrow should point in. If true, the arrow is displayed
293 // above the tab and points down. If false, the arrow is displayed beneath
294 // the tab and points up.
297 // Renders the drop indicator.
298 views::Widget
* arrow_window
;
299 views::ImageView
* arrow_view
;
301 // The URL for the drop event.
304 // Whether the MIME type of the file pointed to by |url| is supported.
308 DISALLOW_COPY_AND_ASSIGN(DropInfo
);
313 // Creates and returns a new tab. The caller owners the returned tab.
316 // Invoked from |AddTabAt| after the newly created tab has been inserted.
317 void StartInsertTabAnimation(int model_index
);
319 // Invoked from |MoveTab| after |tab_data_| has been updated to animate the
321 void StartMoveTabAnimation();
323 // Starts the remove tab animation.
324 void StartRemoveTabAnimation(int model_index
);
326 // Schedules the animations and bounds changes necessary for a remove tab
328 void ScheduleRemoveTabAnimation(Tab
* tab
);
330 // Animates all the views to their ideal bounds.
331 // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds
332 // currently set in ideal_bounds.
333 void AnimateToIdealBounds();
335 // Returns whether the highlight button should be highlighted after a remove.
336 bool ShouldHighlightCloseButtonAfterRemove();
338 // Invoked from Layout if the size changes or layout is really needed.
341 // Drags the active tab by |delta|. |initial_positions| is the x-coordinates
342 // of the tabs when the drag started.
343 void DragActiveTab(const std::vector
<int>& initial_positions
, int delta
);
345 // Sets the ideal bounds x-coordinates to |positions|.
346 void SetIdealBoundsFromPositions(const std::vector
<int>& positions
);
348 // Stacks the dragged tabs. This is used if the drag operation is
349 // MOVE_VISIBILE_TABS and the tabs don't fill the tabstrip. When this happens
350 // the active tab follows the mouse and the other tabs stack around it.
351 void StackDraggedTabs(int delta
);
353 // Returns true if dragging has resulted in temporarily stacking the tabs.
354 bool IsStackingDraggedTabs() const;
356 // Invoked during drag to layout the tabs being dragged in |tabs| at
357 // |location|. If |initial_drag| is true, this is the initial layout after the
358 // user moved the mouse far enough to trigger a drag.
359 void LayoutDraggedTabsAt(const std::vector
<Tab
*>& tabs
,
361 const gfx::Point
& location
,
364 // Calculates the bounds needed for each of the tabs, placing the result in
366 void CalculateBoundsForDraggedTabs(const std::vector
<Tab
*>& tabs
,
367 std::vector
<gfx::Rect
>* bounds
);
369 // Returns the size needed for the specified tabs. This is invoked during drag
370 // and drop to calculate offsets and positioning.
371 int GetSizeNeededForTabs(const std::vector
<Tab
*>& tabs
);
373 // Adds the tab at |index| to |tabs_closing_map_| and removes the tab from
375 void RemoveTabFromViewModel(int index
);
377 // Cleans up the Tab from the TabStrip. This is called from the tab animation
378 // code and is not a general-purpose method.
379 void RemoveAndDeleteTab(Tab
* tab
);
381 // Adjusts the indices of all tabs in |tabs_closing_map_| whose index is
382 // >= |index| to have a new index of |index + delta|.
383 void UpdateTabsClosingMap(int index
, int delta
);
385 // Used by TabDragController when the user starts or stops dragging tabs.
386 void StartedDraggingTabs(const std::vector
<Tab
*>& tabs
);
388 // Invoked when TabDragController detaches a set of tabs.
389 void DraggedTabsDetached();
391 // Used by TabDragController when the user stops dragging tabs. |move_only| is
392 // true if the move behavior is TabDragController::MOVE_VISIBILE_TABS.
393 // |completed| is true if the drag operation completed successfully, false if
395 void StoppedDraggingTabs(const std::vector
<Tab
*>& tabs
,
396 const std::vector
<int>& initial_positions
,
400 // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
401 // |is_first_tab| is set to true.
402 void StoppedDraggingTab(Tab
* tab
, bool* is_first_tab
);
404 // Takes ownership of |controller|.
405 void OwnDragController(TabDragController
* controller
);
407 // Destroys the current TabDragController. This cancel the existing drag
409 void DestroyDragController();
411 // Releases ownership of the current TabDragController.
412 TabDragController
* ReleaseDragController();
414 // Paints all the tabs in |tabs_closing_map_[index]|.
415 void PaintClosingTabs(gfx::Canvas
* canvas
, int index
);
417 // Invoked when a mouse event occurs over |source|. Potentially switches the
419 void UpdateLayoutTypeFromMouseEvent(views::View
* source
,
420 const ui::MouseEvent
& event
);
422 // -- Tab Resize Layout -----------------------------------------------------
424 // Returns the exact (unrounded) current width of each tab.
425 void GetCurrentTabWidths(double* unselected_width
,
426 double* selected_width
) const;
428 // Returns the exact (unrounded) desired width of each tab, based on the
429 // desired strip width and number of tabs. If
430 // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in
431 // calculating the desired strip width; otherwise we use the current width.
432 // |mini_tab_count| gives the number of mini-tabs and |tab_count| the number
433 // of mini and non-mini-tabs.
434 void GetDesiredTabWidths(int tab_count
,
436 double* unselected_width
,
437 double* selected_width
) const;
439 // Perform an animated resize-relayout of the TabStrip immediately.
440 void ResizeLayoutTabs();
442 // Invokes ResizeLayoutTabs() as long as we're not in a drag session. If we
443 // are in a drag session this restarts the timer.
444 void ResizeLayoutTabsFromTouch();
446 // Restarts |resize_layout_timer_|.
447 void StartResizeLayoutTabsFromTouchTimer();
449 // Sets the bounds of the tabs to |tab_bounds|.
450 void SetTabBoundsForDrag(const std::vector
<gfx::Rect
>& tab_bounds
);
452 // Ensure that the message loop observer used for event spying is added and
453 // removed appropriately so we can tell when to resize layout the tab strip.
454 void AddMessageLoopObserver();
455 void RemoveMessageLoopObserver();
457 // -- Link Drag & Drop ------------------------------------------------------
459 // Returns the bounds to render the drop at, in screen coordinates. Sets
460 // |is_beneath| to indicate whether the arrow is beneath the tab, or above
462 gfx::Rect
GetDropBounds(int drop_index
, bool drop_before
, bool* is_beneath
);
464 // Updates the location of the drop based on the event.
465 void UpdateDropIndex(const ui::DropTargetEvent
& event
);
467 // Sets the location of the drop, repainting as necessary.
468 void SetDropIndex(int tab_data_index
, bool drop_before
);
470 // Returns the drop effect for dropping a URL on the tab strip. This does
471 // not query the data in anyway, it only looks at the source operations.
472 int GetDropEffect(const ui::DropTargetEvent
& event
);
474 // Returns the image to use for indicating a drop on a tab. If is_down is
475 // true, this returns an arrow pointing down.
476 static gfx::ImageSkia
* GetDropArrowImage(bool is_down
);
478 // -- Animations ------------------------------------------------------------
480 // Invoked prior to starting a new animation.
481 void PrepareForAnimation();
483 // Generates the ideal bounds for each of the tabs as well as the new tab
485 void GenerateIdealBounds();
487 // Generates the ideal bounds for the mini tabs. Returns the index to position
488 // the first non-mini tab and sets |first_non_mini_index| to the index of the
489 // first non-mini tab.
490 int GenerateIdealBoundsForMiniTabs(int* first_non_mini_index
);
492 // Returns the width needed for the new tab button (and padding).
493 static int new_tab_button_width();
495 // Returns the vertical offset of the tab strip button. This offset applies
496 // only to restored windows.
497 static int button_v_offset();
499 // Returns the width of the area that contains tabs. This does not include
500 // the width of the new tab button.
501 int tab_area_width() const;
503 // Starts various types of TabStrip animations.
504 void StartResizeLayoutAnimation();
505 void StartMiniTabAnimation();
506 void StartMouseInitiatedRemoveTabAnimation(int model_index
);
508 // Returns true if the specified point in TabStrip coords is within the
509 // hit-test region of the specified Tab.
510 bool IsPointInTab(Tab
* tab
, const gfx::Point
& point_in_tabstrip_coords
);
512 // -- Touch Layout ----------------------------------------------------------
514 // Returns the position normal tabs start at.
515 int GetStartXForNormalTabs() const;
517 // Returns the tab to use for event handling. This uses FindTabForEventFrom()
518 // to do the actual searching.
519 Tab
* FindTabForEvent(const gfx::Point
& point
);
521 // Returns the tab to use for event handling starting at index |start| and
522 // iterating by |delta|.
523 Tab
* FindTabForEventFrom(const gfx::Point
& point
, int start
, int delta
);
525 // For a given point, finds a tab that is hit by the point. If the point hits
526 // an area on which two tabs are overlapping, the tab is selected as follows:
527 // - If one of the tabs is active, select it.
528 // - Select the left one.
529 // If no tabs are hit, returns NULL.
530 views::View
* FindTabHitByPoint(const gfx::Point
& point
);
532 // Returns the x-coordinates of the tabs.
533 std::vector
<int> GetTabXCoordinates();
535 // Creates/Destroys |touch_layout_| as necessary.
536 void SwapLayoutIfNecessary();
538 // Returns true if |touch_layout_| is needed.
539 bool NeedsTouchLayout() const;
541 // Sets the value of |reset_to_shrink_on_exit_|. If true |mouse_watcher_| is
542 // used to track when the mouse truly exits the tabstrip and the layout type
544 void SetResetToShrinkOnExit(bool value
);
546 // Should the layout dynamically adjust?
547 bool GetAdjustLayout() const;
549 // -- Member Variables ------------------------------------------------------
551 // There is a one-to-one mapping between each of the tabs in the
552 // TabStripController (TabStripModel) and |tabs_|. Because we animate tab
553 // removal there exists a period of time where a tab is displayed but not in
554 // the model. When this occurs the tab is removed from |tabs_| and placed in
555 // |tabs_closing_map_|. When the animation completes the tab is removed from
556 // |tabs_closing_map_|. The painting code ensures both sets of tabs are
557 // painted, and the event handling code ensures only tabs in |tabs_| are used.
558 views::ViewModel tabs_
;
559 TabsClosingMap tabs_closing_map_
;
561 scoped_ptr
<TabStripController
> controller_
;
563 // The "New Tab" button.
564 NewTabButton
* newtab_button_
;
566 // Ideal bounds of the new tab button.
567 gfx::Rect newtab_button_bounds_
;
569 // The current widths of various types of tabs. We save these so that, as
570 // users close tabs while we're holding them at the same size, we can lay out
571 // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving
572 // them all at their existing, rounded widths.
573 double current_unselected_width_
;
574 double current_selected_width_
;
576 // If this value is nonnegative, it is used in GetDesiredTabWidths() to
577 // calculate how much space in the tab strip to use for tabs. Most of the
578 // time this will be -1, but while we're handling closing a tab via the mouse,
579 // we'll set this to the edge of the last tab before closing, so that if we
580 // are closing the last tab and need to resize immediately, we'll resize only
581 // back to this width, thus once again placing the last tab under the mouse
583 int available_width_for_tabs_
;
585 // True if PrepareForCloseAt has been invoked. When true remove animations
586 // preserve current tab bounds.
589 // Valid for the lifetime of a drag over us.
590 scoped_ptr
<DropInfo
> drop_info_
;
592 // To ensure all tabs pulse at the same time they share the same animation
593 // container. This is that animation container.
594 scoped_refptr
<gfx::AnimationContainer
> animation_container_
;
596 // MouseWatcher is used for two things:
597 // . When a tab is closed to reset the layout.
598 // . When a mouse is used and the layout dynamically adjusts and is currently
599 // TAB_STRIP_LAYOUT_STACKED.
600 scoped_ptr
<views::MouseWatcher
> mouse_watcher_
;
602 // The controller for a drag initiated from a Tab. Valid for the lifetime of
604 scoped_ptr
<TabDragController
> drag_controller_
;
606 views::BoundsAnimator bounds_animator_
;
608 // Size we last layed out at.
609 gfx::Size last_layout_size_
;
611 TabStripLayoutType layout_type_
;
613 // See description above SetLayoutType().
616 // Only used while in touch mode.
617 scoped_ptr
<StackedTabStripLayout
> touch_layout_
;
619 // If true the layout type is set to TAB_STRIP_LAYOUT_SHRINK when the mouse
620 // exits the tabstrip (as determined using MouseWatcher).
621 bool reset_to_shrink_on_exit_
;
623 // Location of the mouse at the time of the last move.
624 gfx::Point last_mouse_move_location_
;
626 // Time of the last mouse move event.
627 base::TimeTicks last_mouse_move_time_
;
629 // Number of mouse moves.
630 int mouse_move_count_
;
632 // Timer used when a tab is closed and we need to relayout. Only used when a
633 // tab close comes from a touch device.
634 base::OneShotTimer
<TabStrip
> resize_layout_timer_
;
636 // True if tabs are painted as rectangular light-bars.
637 bool immersive_style_
;
640 typedef ObserverList
<TabStripObserver
> TabStripObservers
;
641 TabStripObservers observers_
;
643 DISALLOW_COPY_AND_ASSIGN(TabStrip
);
646 #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_