Index: chrome/browser/ui/gtk/tabs/tab_strip_gtk.h |
diff --git a/chrome/browser/ui/gtk/tabs/tab_strip_gtk.h b/chrome/browser/ui/gtk/tabs/tab_strip_gtk.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0a314e3424ff6c59f90450791fbd6f587d8af414 |
--- /dev/null |
+++ b/chrome/browser/ui/gtk/tabs/tab_strip_gtk.h |
@@ -0,0 +1,466 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CHROME_BROWSER_UI_GTK_TABS_TAB_STRIP_GTK_H_ |
+#define CHROME_BROWSER_UI_GTK_TABS_TAB_STRIP_GTK_H_ |
+#pragma once |
+ |
+#include <gtk/gtk.h> |
+#include <vector> |
+ |
+#include "app/gtk_signal.h" |
+#include "base/basictypes.h" |
+#include "base/task.h" |
+#include "base/message_loop.h" |
+#include "chrome/browser/gtk/owned_widget_gtk.h" |
+#include "chrome/browser/gtk/tabstrip_origin_provider.h" |
+#include "chrome/browser/gtk/tabs/tab_gtk.h" |
+#include "chrome/browser/gtk/view_id_util.h" |
+#include "chrome/browser/tabs/tab_strip_model.h" |
+#include "chrome/common/notification_observer.h" |
+#include "gfx/rect.h" |
+ |
+class BrowserWindowGtk; |
+class CustomDrawButton; |
+class DraggedTabControllerGtk; |
+class GtkThemeProvider; |
+ |
+class TabStripGtk : public TabStripModelObserver, |
+ public TabGtk::TabDelegate, |
+ public MessageLoopForUI::Observer, |
+ public NotificationObserver, |
+ public TabstripOriginProvider, |
+ public ViewIDUtil::Delegate { |
+ public: |
+ class TabAnimation; |
+ |
+ TabStripGtk(TabStripModel* model, BrowserWindowGtk* window); |
+ virtual ~TabStripGtk(); |
+ |
+ // Initialize and load the TabStrip into a container. |
+ // TODO(tc): Pass in theme provider so we can properly theme the tabs. |
+ void Init(); |
+ |
+ void Show(); |
+ void Hide(); |
+ |
+ TabStripModel* model() const { return model_; } |
+ |
+ BrowserWindowGtk* window() const { return window_; } |
+ |
+ GtkWidget* widget() const { return tabstrip_.get(); } |
+ |
+ // Returns true if there is an active drag session. |
+ bool IsDragSessionActive() const { return drag_controller_.get() != NULL; } |
+ |
+ // Returns true if a tab is being dragged into this tabstrip. |
+ bool IsActiveDropTarget() const; |
+ |
+ // Sets the bounds of the tabs. |
+ void Layout(); |
+ |
+ // Queues a draw for the tabstrip widget. |
+ void SchedulePaint(); |
+ |
+ // Sets the bounds of the tabstrip. |
+ void SetBounds(const gfx::Rect& bounds); |
+ |
+ // Returns the bounds of the tabstrip. |
+ const gfx::Rect& bounds() const { return bounds_; } |
+ |
+ // Updates loading animations for the TabStrip. |
+ void UpdateLoadingAnimations(); |
+ |
+ // Return true if this tab strip is compatible with the provided tab strip. |
+ // Compatible tab strips can transfer tabs during drag and drop. |
+ bool IsCompatibleWith(TabStripGtk* other); |
+ |
+ // Returns true if Tabs in this TabStrip are currently changing size or |
+ // position. |
+ bool IsAnimating() const; |
+ |
+ // Destroys the active drag controller. |
+ void DestroyDragController(); |
+ |
+ // Removes the drag source tab from this tabstrip, and deletes it. |
+ void DestroyDraggedSourceTab(TabGtk* tab); |
+ |
+ // Retrieve the ideal bounds for the Tab at the specified index. |
+ gfx::Rect GetIdealBounds(int index); |
+ |
+ // Sets the vertical offset that each tab will use to offset against the |
+ // background image. Passed in from the titlebar and based on the size of the |
+ // alignment that sits above the tabstrip. |
+ void SetVerticalOffset(int offset); |
+ |
+ // TabstripOriginProvider implementation ------------------------------------- |
+ virtual gfx::Point GetTabStripOriginForWidget(GtkWidget* widget); |
+ |
+ // ViewIDUtil::Delegate implementation --------------------------------------- |
+ virtual GtkWidget* GetWidgetForViewID(ViewID id); |
+ |
+ protected: |
+ // TabStripModelObserver implementation: |
+ virtual void TabInsertedAt(TabContentsWrapper* contents, |
+ int index, |
+ bool foreground); |
+ virtual void TabDetachedAt(TabContentsWrapper* contents, int index); |
+ virtual void TabSelectedAt(TabContentsWrapper* old_contents, |
+ TabContentsWrapper* contents, |
+ int index, |
+ bool user_gesture); |
+ virtual void TabMoved(TabContentsWrapper* contents, |
+ int from_index, |
+ int to_index); |
+ virtual void TabChangedAt(TabContentsWrapper* contents, int index, |
+ TabChangeType change_type); |
+ virtual void TabReplacedAt(TabStripModel* tab_strip_model, |
+ TabContentsWrapper* old_contents, |
+ TabContentsWrapper* new_contents, |
+ int index); |
+ virtual void TabMiniStateChanged(TabContentsWrapper* contents, int index); |
+ virtual void TabBlockedStateChanged(TabContentsWrapper* contents, |
+ int index); |
+ |
+ // TabGtk::TabDelegate implementation: |
+ virtual bool IsTabSelected(const TabGtk* tab) const; |
+ virtual bool IsTabPinned(const TabGtk* tab) const; |
+ virtual bool IsTabDetached(const TabGtk* tab) const; |
+ virtual void SelectTab(TabGtk* tab); |
+ virtual void CloseTab(TabGtk* tab); |
+ virtual bool IsCommandEnabledForTab( |
+ TabStripModel::ContextMenuCommand command_id, const TabGtk* tab) const; |
+ virtual void ExecuteCommandForTab( |
+ TabStripModel::ContextMenuCommand command_id, TabGtk* tab); |
+ virtual void StartHighlightTabsForCommand( |
+ TabStripModel::ContextMenuCommand command_id, TabGtk* tab); |
+ virtual void StopHighlightTabsForCommand( |
+ TabStripModel::ContextMenuCommand command_id, TabGtk* tab); |
+ virtual void StopAllHighlighting(); |
+ virtual void MaybeStartDrag(TabGtk* tab, const gfx::Point& point); |
+ virtual void ContinueDrag(GdkDragContext* context); |
+ virtual bool EndDrag(bool canceled); |
+ virtual bool HasAvailableDragActions() const; |
+ virtual ThemeProvider* GetThemeProvider(); |
+ |
+ // MessageLoop::Observer implementation: |
+ virtual void WillProcessEvent(GdkEvent* event); |
+ virtual void DidProcessEvent(GdkEvent* event); |
+ |
+ // Overridden from NotificationObserver: |
+ virtual void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details); |
+ |
+ // Horizontal gap between mini-tabs and normal tabs. |
+ static const int mini_to_non_mini_gap_; |
+ |
+ private: |
+ friend class BrowserWindowGtk; |
+ friend class DraggedTabControllerGtk; |
+ friend class InsertTabAnimation; |
+ friend class MiniMoveAnimation; |
+ friend class MiniTabAnimation; |
+ friend class MoveTabAnimation; |
+ friend class RemoveTabAnimation; |
+ friend class ResizeLayoutAnimation; |
+ friend class TabAnimation; |
+ |
+ struct TabData { |
+ TabGtk* tab; |
+ gfx::Rect ideal_bounds; |
+ }; |
+ |
+ // Used during a drop session of a url. Tracks the position of the drop as |
+ // well as a window used to highlight where the drop occurs. |
+ class DropInfo { |
+ public: |
+ DropInfo(int index, bool drop_before, bool point_down); |
+ virtual ~DropInfo(); |
+ |
+ // TODO(jhawkins): Factor out this code into a TransparentContainer class. |
+ |
+ // expose-event handler that redraws the drop indicator. |
+ CHROMEGTK_CALLBACK_1(DropInfo, gboolean, OnExposeEvent, GdkEventExpose*); |
+ |
+ // Sets the color map of the container window to allow the window to be |
+ // transparent. |
+ void SetContainerColorMap(); |
+ |
+ // Sets full transparency for the container window. This is used if |
+ // compositing is available for the screen. |
+ void SetContainerTransparency(); |
+ |
+ // Sets the shape mask for the container window to emulate a transparent |
+ // container window. This is used if compositing is not available for the |
+ // screen. |
+ void SetContainerShapeMask(); |
+ |
+ // Creates the container widget. |
+ void CreateContainer(); |
+ |
+ // Destroys the container widget. |
+ void DestroyContainer(); |
+ |
+ // Index of the tab to drop on. If drop_before is true, the drop should |
+ // occur between the tab at drop_index - 1 and drop_index. |
+ // WARNING: if drop_before is true it is possible this will == tab_count, |
+ // which indicates the drop should create a new tab at the end of the tabs. |
+ int drop_index; |
+ bool drop_before; |
+ |
+ // Direction the arrow should point in. If true, the arrow is displayed |
+ // above the tab and points down. If false, the arrow is displayed beneath |
+ // the tab and points up. |
+ bool point_down; |
+ |
+ // Transparent container window used to render the drop indicator over the |
+ // tabstrip and toolbar. |
+ GtkWidget* container; |
+ |
+ // The drop indicator image. |
+ GdkPixbuf* drop_arrow; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(DropInfo); |
+ }; |
+ |
+ // expose-event handler that redraws the tabstrip |
+ CHROMEGTK_CALLBACK_1(TabStripGtk, gboolean, OnExpose, GdkEventExpose*); |
+ |
+ // size-allocate handler that gets the new bounds of the tabstrip. |
+ CHROMEGTK_CALLBACK_1(TabStripGtk, void, OnSizeAllocate, GtkAllocation*); |
+ |
+ // drag-motion handler that is signaled when the user performs a drag in the |
+ // tabstrip bounds. |
+ CHROMEGTK_CALLBACK_4(TabStripGtk, gboolean, OnDragMotion, GdkDragContext*, |
+ gint, gint, guint); |
+ |
+ // drag-drop handler that is notified when the user finishes a drag. |
+ CHROMEGTK_CALLBACK_4(TabStripGtk, gboolean, OnDragDrop, GdkDragContext*, |
+ gint, gint, guint); |
+ |
+ // drag-leave handler that is signaled when the mouse leaves the tabstrip |
+ // during a drag. |
+ CHROMEGTK_CALLBACK_2(TabStripGtk, gboolean, OnDragLeave, GdkDragContext*, |
+ guint); |
+ |
+ // drag-data-received handler that receives the data associated with the drag. |
+ CHROMEGTK_CALLBACK_6(TabStripGtk, gboolean, OnDragDataReceived, |
+ GdkDragContext*, gint, gint, GtkSelectionData*, |
+ guint, guint); |
+ |
+ // Handles the clicked signal from the new tab button. |
+ CHROMEGTK_CALLBACK_0(TabStripGtk, void, OnNewTabClicked); |
+ |
+ // Sets the bounds of the tab and moves the tab widget to those bounds. |
+ void SetTabBounds(TabGtk* tab, const gfx::Rect& bounds); |
+ |
+ // Returns true if |rects| are all areas that match up with tab favicons. |
+ // |rects| must be sorted from left to right. |tabs_to_paint| are the tab |
+ // positions that match the rects. |
+ bool CanPaintOnlyFavIcons(const GdkRectangle* rects, |
+ int num_rects, |
+ std::vector<int>* tabs_to_paint); |
+ |
+ // Paints the tab favicon areas for tabs in |tabs_to_paint|. |
+ void PaintOnlyFavIcons(GdkEventExpose* event, |
+ const std::vector<int>& tabs_to_paint); |
+ |
+ // Initializes the new tab button. |
+ CustomDrawButton* MakeNewTabButton(); |
+ |
+ // Gets the number of Tabs in the collection. |
+ int GetTabCount() const; |
+ |
+ // Returns the number of mini-tabs. |
+ int GetMiniTabCount() const; |
+ |
+ // Retrieves the Tab at the specified index. Take care in using this, you may |
+ // need to use GetTabAtAdjustForAnimation. |
+ TabGtk* GetTabAt(int index) const; |
+ |
+ // Returns the tab at the specified index. If a remove animation is on going |
+ // and the index is >= the index of the tab being removed, the index is |
+ // incremented. While a remove operation is on going the indices of the model |
+ // do not line up with the indices of the view. This method adjusts the index |
+ // accordingly. |
+ // |
+ // Use this instead of GetTabAt if the index comes from the model. |
+ TabGtk* GetTabAtAdjustForAnimation(int index) const; |
+ |
+ // Returns the exact (unrounded) current width of each tab. |
+ void GetCurrentTabWidths(double* unselected_width, |
+ double* selected_width) const; |
+ |
+ // Returns the exact (unrounded) desired width of each tab, based on the |
+ // desired strip width and number of tabs. If |
+ // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in |
+ // calculating the desired strip width; otherwise we use the current width. |
+ // |mini_tab_count| gives the number of mini-tabs, and |tab_count| the |
+ // number of mini and non-mini-tabs. |
+ void GetDesiredTabWidths(int tab_count, |
+ int mini_tab_count, |
+ double* unselected_width, |
+ double* selected_width) const; |
+ |
+ // Returns the horizontal offset before the tab at |tab_index|. |
+ int GetTabHOffset(int tab_index); |
+ |
+ // Returns the x-coordinate tabs start from. |
+ int tab_start_x() const; |
+ |
+ // Perform an animated resize-relayout of the TabStrip immediately. The |
+ // value returned indicates whether a resize actually took place. |
+ bool ResizeLayoutTabs(); |
+ |
+ // Returns whether or not the cursor is currently in the "tab strip zone" |
+ // which is defined as the region above the TabStrip and a bit below it. |
+ bool IsCursorInTabStripZone() const; |
+ |
+ // Ensure that the message loop observer used for event spying is added and |
+ // removed appropriately so we can tell when to resize layout the tab strip. |
+ void AddMessageLoopObserver(); |
+ void RemoveMessageLoopObserver(); |
+ |
+ // Calculates the available width for tabs, assuming a Tab is to be closed. |
+ int GetAvailableWidthForTabs(TabGtk* last_tab) const; |
+ |
+ // Finds the index of the TabContents corresponding to |tab| in our |
+ // associated TabStripModel, or -1 if there is none (e.g. the specified |tab| |
+ // is being animated closed). |
+ int GetIndexOfTab(const TabGtk* tab) const; |
+ |
+ // Cleans up the tab from the TabStrip at the specified |index|. |
+ void RemoveTabAt(int index); |
+ |
+ // Called from the message loop observer when a mouse movement has occurred |
+ // anywhere over our containing window. |
+ void HandleGlobalMouseMoveEvent(); |
+ |
+ // Generates the ideal bounds of the TabStrip when all Tabs have finished |
+ // animating to their desired position/bounds. This is used by the standard |
+ // Layout method and other callers like the DraggedTabController that need |
+ // stable representations of Tab positions. |
+ void GenerateIdealBounds(); |
+ |
+ // Lays out the New Tab button, assuming the right edge of the last Tab on |
+ // the TabStrip at |last_tab_right|. |unselected_width| is the width of |
+ // unselected tabs at the moment this function is called. The value changes |
+ // during animations, so we can't use current_unselected_width_. |
+ void LayoutNewTabButton(double last_tab_right, double unselected_width); |
+ |
+ // -- Link Drag & Drop ------------------------------------------------------ |
+ |
+ // Returns the bounds to render the drop at, in screen coordinates. Sets |
+ // |is_beneath| to indicate whether the arrow is beneath the tab, or above |
+ // it. |
+ gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath); |
+ |
+ // Updates the location of the drop based on the event. |
+ void UpdateDropIndex(GdkDragContext* context, gint x, gint y); |
+ |
+ // Sets the location of the drop, repainting as necessary. |
+ void SetDropIndex(int index, bool drop_before); |
+ |
+ // Determines whether the data is acceptable by the tabstrip and opens a new |
+ // tab with the data as URL if it is. Returns true if the drop was |
+ // successful. |
+ bool CompleteDrop(guchar* data, bool is_plain_text); |
+ |
+ // Returns the image to use for indicating a drop on a tab. If is_down is |
+ // true, this returns an arrow pointing down. |
+ static GdkPixbuf* GetDropArrowImage(bool is_down); |
+ |
+ // -- Animations ------------------------------------------------------------- |
+ |
+ // Stops the current animation. |
+ void StopAnimation(); |
+ |
+ // A generic Layout method for various classes of TabStrip animations, |
+ // including Insert, Remove and Resize Layout cases. |
+ void AnimationLayout(double unselected_width); |
+ |
+ // Starts various types of TabStrip animations. |
+ void StartInsertTabAnimation(int index); |
+ void StartRemoveTabAnimation(int index, TabContents* contents); |
+ void StartMoveTabAnimation(int from_index, int to_index); |
+ void StartMiniTabAnimation(int index); |
+ void StartMiniMoveTabAnimation(int from_index, |
+ int to_index, |
+ const gfx::Rect& start_bounds); |
+ void StartResizeLayoutAnimation(); |
+ |
+ // Notifies the TabStrip that the specified TabAnimation has completed. |
+ // Optionally a full Layout will be performed, specified by |layout|. |
+ void FinishAnimation(TabAnimation* animation, bool layout); |
+ |
+ NotificationRegistrar registrar_; |
+ |
+ // The Tabs we contain, and their last generated "good" bounds. |
+ std::vector<TabData> tab_data_; |
+ |
+ // The current widths of various types of tabs. We save these so that, as |
+ // users close tabs while we're holding them at the same size, we can lay out |
+ // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving |
+ // them all at their existing, rounded widths. |
+ double current_unselected_width_; |
+ double current_selected_width_; |
+ |
+ // If this value is nonnegative, it is used in GetDesiredTabWidths() to |
+ // calculate how much space in the tab strip to use for tabs. Most of the |
+ // time this will be -1, but while we're handling closing a tab via the mouse, |
+ // we'll set this to the edge of the last tab before closing, so that if we |
+ // are closing the last tab and need to resize immediately, we'll resize only |
+ // back to this width, thus once again placing the last tab under the mouse |
+ // cursor. |
+ int available_width_for_tabs_; |
+ |
+ // True if a resize layout animation should be run a short delay after the |
+ // mouse exits the TabStrip. |
+ bool needs_resize_layout_; |
+ |
+ // The GtkFixed widget. |
+ OwnedWidgetGtk tabstrip_; |
+ |
+ // The bounds of the tabstrip. |
+ gfx::Rect bounds_; |
+ |
+ // The amount to offset tab backgrounds when we are using an autogenerated |
+ // tab background image. |
+ int tab_vertical_offset_; |
+ |
+ // Our model. |
+ TabStripModel* model_; |
+ |
+ // The BrowserWindowGtk containing this tab strip. |
+ BrowserWindowGtk* window_; |
+ |
+ // Theme resources. |
+ GtkThemeProvider* theme_provider_; |
+ |
+ // The currently running animation. |
+ scoped_ptr<TabAnimation> active_animation_; |
+ |
+ // The New Tab button. |
+ scoped_ptr<CustomDrawButton> newtab_button_; |
+ |
+ // Valid for the lifetime of a drag over us. |
+ scoped_ptr<DropInfo> drop_info_; |
+ |
+ // The controller for a drag initiated from a Tab. Valid for the lifetime of |
+ // the drag session. |
+ scoped_ptr<DraggedTabControllerGtk> drag_controller_; |
+ |
+ // A factory that is used to construct a delayed callback to the |
+ // ResizeLayoutTabsNow method. |
+ ScopedRunnableMethodFactory<TabStripGtk> resize_layout_factory_; |
+ |
+ // True if the tabstrip has already been added as a MessageLoop observer. |
+ bool added_as_message_loop_observer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TabStripGtk); |
+}; |
+ |
+#endif // CHROME_BROWSER_UI_GTK_TABS_TAB_STRIP_GTK_H_ |