OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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_GTK_TABS_TAB_STRIP_GTK_H_ |
| 6 #define CHROME_BROWSER_UI_GTK_TABS_TAB_STRIP_GTK_H_ |
| 7 #pragma once |
| 8 |
| 9 #include <gtk/gtk.h> |
| 10 #include <vector> |
| 11 |
| 12 #include "app/gtk_signal.h" |
| 13 #include "base/basictypes.h" |
| 14 #include "base/task.h" |
| 15 #include "base/message_loop.h" |
| 16 #include "chrome/browser/gtk/owned_widget_gtk.h" |
| 17 #include "chrome/browser/gtk/tabstrip_origin_provider.h" |
| 18 #include "chrome/browser/gtk/tabs/tab_gtk.h" |
| 19 #include "chrome/browser/gtk/view_id_util.h" |
| 20 #include "chrome/browser/tabs/tab_strip_model.h" |
| 21 #include "chrome/common/notification_observer.h" |
| 22 #include "gfx/rect.h" |
| 23 |
| 24 class BrowserWindowGtk; |
| 25 class CustomDrawButton; |
| 26 class DraggedTabControllerGtk; |
| 27 class GtkThemeProvider; |
| 28 |
| 29 class TabStripGtk : public TabStripModelObserver, |
| 30 public TabGtk::TabDelegate, |
| 31 public MessageLoopForUI::Observer, |
| 32 public NotificationObserver, |
| 33 public TabstripOriginProvider, |
| 34 public ViewIDUtil::Delegate { |
| 35 public: |
| 36 class TabAnimation; |
| 37 |
| 38 TabStripGtk(TabStripModel* model, BrowserWindowGtk* window); |
| 39 virtual ~TabStripGtk(); |
| 40 |
| 41 // Initialize and load the TabStrip into a container. |
| 42 // TODO(tc): Pass in theme provider so we can properly theme the tabs. |
| 43 void Init(); |
| 44 |
| 45 void Show(); |
| 46 void Hide(); |
| 47 |
| 48 TabStripModel* model() const { return model_; } |
| 49 |
| 50 BrowserWindowGtk* window() const { return window_; } |
| 51 |
| 52 GtkWidget* widget() const { return tabstrip_.get(); } |
| 53 |
| 54 // Returns true if there is an active drag session. |
| 55 bool IsDragSessionActive() const { return drag_controller_.get() != NULL; } |
| 56 |
| 57 // Returns true if a tab is being dragged into this tabstrip. |
| 58 bool IsActiveDropTarget() const; |
| 59 |
| 60 // Sets the bounds of the tabs. |
| 61 void Layout(); |
| 62 |
| 63 // Queues a draw for the tabstrip widget. |
| 64 void SchedulePaint(); |
| 65 |
| 66 // Sets the bounds of the tabstrip. |
| 67 void SetBounds(const gfx::Rect& bounds); |
| 68 |
| 69 // Returns the bounds of the tabstrip. |
| 70 const gfx::Rect& bounds() const { return bounds_; } |
| 71 |
| 72 // Updates loading animations for the TabStrip. |
| 73 void UpdateLoadingAnimations(); |
| 74 |
| 75 // Return true if this tab strip is compatible with the provided tab strip. |
| 76 // Compatible tab strips can transfer tabs during drag and drop. |
| 77 bool IsCompatibleWith(TabStripGtk* other); |
| 78 |
| 79 // Returns true if Tabs in this TabStrip are currently changing size or |
| 80 // position. |
| 81 bool IsAnimating() const; |
| 82 |
| 83 // Destroys the active drag controller. |
| 84 void DestroyDragController(); |
| 85 |
| 86 // Removes the drag source tab from this tabstrip, and deletes it. |
| 87 void DestroyDraggedSourceTab(TabGtk* tab); |
| 88 |
| 89 // Retrieve the ideal bounds for the Tab at the specified index. |
| 90 gfx::Rect GetIdealBounds(int index); |
| 91 |
| 92 // Sets the vertical offset that each tab will use to offset against the |
| 93 // background image. Passed in from the titlebar and based on the size of the |
| 94 // alignment that sits above the tabstrip. |
| 95 void SetVerticalOffset(int offset); |
| 96 |
| 97 // TabstripOriginProvider implementation ------------------------------------- |
| 98 virtual gfx::Point GetTabStripOriginForWidget(GtkWidget* widget); |
| 99 |
| 100 // ViewIDUtil::Delegate implementation --------------------------------------- |
| 101 virtual GtkWidget* GetWidgetForViewID(ViewID id); |
| 102 |
| 103 protected: |
| 104 // TabStripModelObserver implementation: |
| 105 virtual void TabInsertedAt(TabContentsWrapper* contents, |
| 106 int index, |
| 107 bool foreground); |
| 108 virtual void TabDetachedAt(TabContentsWrapper* contents, int index); |
| 109 virtual void TabSelectedAt(TabContentsWrapper* old_contents, |
| 110 TabContentsWrapper* contents, |
| 111 int index, |
| 112 bool user_gesture); |
| 113 virtual void TabMoved(TabContentsWrapper* contents, |
| 114 int from_index, |
| 115 int to_index); |
| 116 virtual void TabChangedAt(TabContentsWrapper* contents, int index, |
| 117 TabChangeType change_type); |
| 118 virtual void TabReplacedAt(TabStripModel* tab_strip_model, |
| 119 TabContentsWrapper* old_contents, |
| 120 TabContentsWrapper* new_contents, |
| 121 int index); |
| 122 virtual void TabMiniStateChanged(TabContentsWrapper* contents, int index); |
| 123 virtual void TabBlockedStateChanged(TabContentsWrapper* contents, |
| 124 int index); |
| 125 |
| 126 // TabGtk::TabDelegate implementation: |
| 127 virtual bool IsTabSelected(const TabGtk* tab) const; |
| 128 virtual bool IsTabPinned(const TabGtk* tab) const; |
| 129 virtual bool IsTabDetached(const TabGtk* tab) const; |
| 130 virtual void SelectTab(TabGtk* tab); |
| 131 virtual void CloseTab(TabGtk* tab); |
| 132 virtual bool IsCommandEnabledForTab( |
| 133 TabStripModel::ContextMenuCommand command_id, const TabGtk* tab) const; |
| 134 virtual void ExecuteCommandForTab( |
| 135 TabStripModel::ContextMenuCommand command_id, TabGtk* tab); |
| 136 virtual void StartHighlightTabsForCommand( |
| 137 TabStripModel::ContextMenuCommand command_id, TabGtk* tab); |
| 138 virtual void StopHighlightTabsForCommand( |
| 139 TabStripModel::ContextMenuCommand command_id, TabGtk* tab); |
| 140 virtual void StopAllHighlighting(); |
| 141 virtual void MaybeStartDrag(TabGtk* tab, const gfx::Point& point); |
| 142 virtual void ContinueDrag(GdkDragContext* context); |
| 143 virtual bool EndDrag(bool canceled); |
| 144 virtual bool HasAvailableDragActions() const; |
| 145 virtual ThemeProvider* GetThemeProvider(); |
| 146 |
| 147 // MessageLoop::Observer implementation: |
| 148 virtual void WillProcessEvent(GdkEvent* event); |
| 149 virtual void DidProcessEvent(GdkEvent* event); |
| 150 |
| 151 // Overridden from NotificationObserver: |
| 152 virtual void Observe(NotificationType type, |
| 153 const NotificationSource& source, |
| 154 const NotificationDetails& details); |
| 155 |
| 156 // Horizontal gap between mini-tabs and normal tabs. |
| 157 static const int mini_to_non_mini_gap_; |
| 158 |
| 159 private: |
| 160 friend class BrowserWindowGtk; |
| 161 friend class DraggedTabControllerGtk; |
| 162 friend class InsertTabAnimation; |
| 163 friend class MiniMoveAnimation; |
| 164 friend class MiniTabAnimation; |
| 165 friend class MoveTabAnimation; |
| 166 friend class RemoveTabAnimation; |
| 167 friend class ResizeLayoutAnimation; |
| 168 friend class TabAnimation; |
| 169 |
| 170 struct TabData { |
| 171 TabGtk* tab; |
| 172 gfx::Rect ideal_bounds; |
| 173 }; |
| 174 |
| 175 // Used during a drop session of a url. Tracks the position of the drop as |
| 176 // well as a window used to highlight where the drop occurs. |
| 177 class DropInfo { |
| 178 public: |
| 179 DropInfo(int index, bool drop_before, bool point_down); |
| 180 virtual ~DropInfo(); |
| 181 |
| 182 // TODO(jhawkins): Factor out this code into a TransparentContainer class. |
| 183 |
| 184 // expose-event handler that redraws the drop indicator. |
| 185 CHROMEGTK_CALLBACK_1(DropInfo, gboolean, OnExposeEvent, GdkEventExpose*); |
| 186 |
| 187 // Sets the color map of the container window to allow the window to be |
| 188 // transparent. |
| 189 void SetContainerColorMap(); |
| 190 |
| 191 // Sets full transparency for the container window. This is used if |
| 192 // compositing is available for the screen. |
| 193 void SetContainerTransparency(); |
| 194 |
| 195 // Sets the shape mask for the container window to emulate a transparent |
| 196 // container window. This is used if compositing is not available for the |
| 197 // screen. |
| 198 void SetContainerShapeMask(); |
| 199 |
| 200 // Creates the container widget. |
| 201 void CreateContainer(); |
| 202 |
| 203 // Destroys the container widget. |
| 204 void DestroyContainer(); |
| 205 |
| 206 // Index of the tab to drop on. If drop_before is true, the drop should |
| 207 // occur between the tab at drop_index - 1 and drop_index. |
| 208 // WARNING: if drop_before is true it is possible this will == tab_count, |
| 209 // which indicates the drop should create a new tab at the end of the tabs. |
| 210 int drop_index; |
| 211 bool drop_before; |
| 212 |
| 213 // Direction the arrow should point in. If true, the arrow is displayed |
| 214 // above the tab and points down. If false, the arrow is displayed beneath |
| 215 // the tab and points up. |
| 216 bool point_down; |
| 217 |
| 218 // Transparent container window used to render the drop indicator over the |
| 219 // tabstrip and toolbar. |
| 220 GtkWidget* container; |
| 221 |
| 222 // The drop indicator image. |
| 223 GdkPixbuf* drop_arrow; |
| 224 |
| 225 private: |
| 226 DISALLOW_COPY_AND_ASSIGN(DropInfo); |
| 227 }; |
| 228 |
| 229 // expose-event handler that redraws the tabstrip |
| 230 CHROMEGTK_CALLBACK_1(TabStripGtk, gboolean, OnExpose, GdkEventExpose*); |
| 231 |
| 232 // size-allocate handler that gets the new bounds of the tabstrip. |
| 233 CHROMEGTK_CALLBACK_1(TabStripGtk, void, OnSizeAllocate, GtkAllocation*); |
| 234 |
| 235 // drag-motion handler that is signaled when the user performs a drag in the |
| 236 // tabstrip bounds. |
| 237 CHROMEGTK_CALLBACK_4(TabStripGtk, gboolean, OnDragMotion, GdkDragContext*, |
| 238 gint, gint, guint); |
| 239 |
| 240 // drag-drop handler that is notified when the user finishes a drag. |
| 241 CHROMEGTK_CALLBACK_4(TabStripGtk, gboolean, OnDragDrop, GdkDragContext*, |
| 242 gint, gint, guint); |
| 243 |
| 244 // drag-leave handler that is signaled when the mouse leaves the tabstrip |
| 245 // during a drag. |
| 246 CHROMEGTK_CALLBACK_2(TabStripGtk, gboolean, OnDragLeave, GdkDragContext*, |
| 247 guint); |
| 248 |
| 249 // drag-data-received handler that receives the data associated with the drag. |
| 250 CHROMEGTK_CALLBACK_6(TabStripGtk, gboolean, OnDragDataReceived, |
| 251 GdkDragContext*, gint, gint, GtkSelectionData*, |
| 252 guint, guint); |
| 253 |
| 254 // Handles the clicked signal from the new tab button. |
| 255 CHROMEGTK_CALLBACK_0(TabStripGtk, void, OnNewTabClicked); |
| 256 |
| 257 // Sets the bounds of the tab and moves the tab widget to those bounds. |
| 258 void SetTabBounds(TabGtk* tab, const gfx::Rect& bounds); |
| 259 |
| 260 // Returns true if |rects| are all areas that match up with tab favicons. |
| 261 // |rects| must be sorted from left to right. |tabs_to_paint| are the tab |
| 262 // positions that match the rects. |
| 263 bool CanPaintOnlyFavIcons(const GdkRectangle* rects, |
| 264 int num_rects, |
| 265 std::vector<int>* tabs_to_paint); |
| 266 |
| 267 // Paints the tab favicon areas for tabs in |tabs_to_paint|. |
| 268 void PaintOnlyFavIcons(GdkEventExpose* event, |
| 269 const std::vector<int>& tabs_to_paint); |
| 270 |
| 271 // Initializes the new tab button. |
| 272 CustomDrawButton* MakeNewTabButton(); |
| 273 |
| 274 // Gets the number of Tabs in the collection. |
| 275 int GetTabCount() const; |
| 276 |
| 277 // Returns the number of mini-tabs. |
| 278 int GetMiniTabCount() const; |
| 279 |
| 280 // Retrieves the Tab at the specified index. Take care in using this, you may |
| 281 // need to use GetTabAtAdjustForAnimation. |
| 282 TabGtk* GetTabAt(int index) const; |
| 283 |
| 284 // Returns the tab at the specified index. If a remove animation is on going |
| 285 // and the index is >= the index of the tab being removed, the index is |
| 286 // incremented. While a remove operation is on going the indices of the model |
| 287 // do not line up with the indices of the view. This method adjusts the index |
| 288 // accordingly. |
| 289 // |
| 290 // Use this instead of GetTabAt if the index comes from the model. |
| 291 TabGtk* GetTabAtAdjustForAnimation(int index) const; |
| 292 |
| 293 // Returns the exact (unrounded) current width of each tab. |
| 294 void GetCurrentTabWidths(double* unselected_width, |
| 295 double* selected_width) const; |
| 296 |
| 297 // Returns the exact (unrounded) desired width of each tab, based on the |
| 298 // desired strip width and number of tabs. If |
| 299 // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in |
| 300 // calculating the desired strip width; otherwise we use the current width. |
| 301 // |mini_tab_count| gives the number of mini-tabs, and |tab_count| the |
| 302 // number of mini and non-mini-tabs. |
| 303 void GetDesiredTabWidths(int tab_count, |
| 304 int mini_tab_count, |
| 305 double* unselected_width, |
| 306 double* selected_width) const; |
| 307 |
| 308 // Returns the horizontal offset before the tab at |tab_index|. |
| 309 int GetTabHOffset(int tab_index); |
| 310 |
| 311 // Returns the x-coordinate tabs start from. |
| 312 int tab_start_x() const; |
| 313 |
| 314 // Perform an animated resize-relayout of the TabStrip immediately. The |
| 315 // value returned indicates whether a resize actually took place. |
| 316 bool ResizeLayoutTabs(); |
| 317 |
| 318 // Returns whether or not the cursor is currently in the "tab strip zone" |
| 319 // which is defined as the region above the TabStrip and a bit below it. |
| 320 bool IsCursorInTabStripZone() const; |
| 321 |
| 322 // Ensure that the message loop observer used for event spying is added and |
| 323 // removed appropriately so we can tell when to resize layout the tab strip. |
| 324 void AddMessageLoopObserver(); |
| 325 void RemoveMessageLoopObserver(); |
| 326 |
| 327 // Calculates the available width for tabs, assuming a Tab is to be closed. |
| 328 int GetAvailableWidthForTabs(TabGtk* last_tab) const; |
| 329 |
| 330 // Finds the index of the TabContents corresponding to |tab| in our |
| 331 // associated TabStripModel, or -1 if there is none (e.g. the specified |tab| |
| 332 // is being animated closed). |
| 333 int GetIndexOfTab(const TabGtk* tab) const; |
| 334 |
| 335 // Cleans up the tab from the TabStrip at the specified |index|. |
| 336 void RemoveTabAt(int index); |
| 337 |
| 338 // Called from the message loop observer when a mouse movement has occurred |
| 339 // anywhere over our containing window. |
| 340 void HandleGlobalMouseMoveEvent(); |
| 341 |
| 342 // Generates the ideal bounds of the TabStrip when all Tabs have finished |
| 343 // animating to their desired position/bounds. This is used by the standard |
| 344 // Layout method and other callers like the DraggedTabController that need |
| 345 // stable representations of Tab positions. |
| 346 void GenerateIdealBounds(); |
| 347 |
| 348 // Lays out the New Tab button, assuming the right edge of the last Tab on |
| 349 // the TabStrip at |last_tab_right|. |unselected_width| is the width of |
| 350 // unselected tabs at the moment this function is called. The value changes |
| 351 // during animations, so we can't use current_unselected_width_. |
| 352 void LayoutNewTabButton(double last_tab_right, double unselected_width); |
| 353 |
| 354 // -- Link Drag & Drop ------------------------------------------------------ |
| 355 |
| 356 // Returns the bounds to render the drop at, in screen coordinates. Sets |
| 357 // |is_beneath| to indicate whether the arrow is beneath the tab, or above |
| 358 // it. |
| 359 gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath); |
| 360 |
| 361 // Updates the location of the drop based on the event. |
| 362 void UpdateDropIndex(GdkDragContext* context, gint x, gint y); |
| 363 |
| 364 // Sets the location of the drop, repainting as necessary. |
| 365 void SetDropIndex(int index, bool drop_before); |
| 366 |
| 367 // Determines whether the data is acceptable by the tabstrip and opens a new |
| 368 // tab with the data as URL if it is. Returns true if the drop was |
| 369 // successful. |
| 370 bool CompleteDrop(guchar* data, bool is_plain_text); |
| 371 |
| 372 // Returns the image to use for indicating a drop on a tab. If is_down is |
| 373 // true, this returns an arrow pointing down. |
| 374 static GdkPixbuf* GetDropArrowImage(bool is_down); |
| 375 |
| 376 // -- Animations ------------------------------------------------------------- |
| 377 |
| 378 // Stops the current animation. |
| 379 void StopAnimation(); |
| 380 |
| 381 // A generic Layout method for various classes of TabStrip animations, |
| 382 // including Insert, Remove and Resize Layout cases. |
| 383 void AnimationLayout(double unselected_width); |
| 384 |
| 385 // Starts various types of TabStrip animations. |
| 386 void StartInsertTabAnimation(int index); |
| 387 void StartRemoveTabAnimation(int index, TabContents* contents); |
| 388 void StartMoveTabAnimation(int from_index, int to_index); |
| 389 void StartMiniTabAnimation(int index); |
| 390 void StartMiniMoveTabAnimation(int from_index, |
| 391 int to_index, |
| 392 const gfx::Rect& start_bounds); |
| 393 void StartResizeLayoutAnimation(); |
| 394 |
| 395 // Notifies the TabStrip that the specified TabAnimation has completed. |
| 396 // Optionally a full Layout will be performed, specified by |layout|. |
| 397 void FinishAnimation(TabAnimation* animation, bool layout); |
| 398 |
| 399 NotificationRegistrar registrar_; |
| 400 |
| 401 // The Tabs we contain, and their last generated "good" bounds. |
| 402 std::vector<TabData> tab_data_; |
| 403 |
| 404 // The current widths of various types of tabs. We save these so that, as |
| 405 // users close tabs while we're holding them at the same size, we can lay out |
| 406 // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving |
| 407 // them all at their existing, rounded widths. |
| 408 double current_unselected_width_; |
| 409 double current_selected_width_; |
| 410 |
| 411 // If this value is nonnegative, it is used in GetDesiredTabWidths() to |
| 412 // calculate how much space in the tab strip to use for tabs. Most of the |
| 413 // time this will be -1, but while we're handling closing a tab via the mouse, |
| 414 // we'll set this to the edge of the last tab before closing, so that if we |
| 415 // are closing the last tab and need to resize immediately, we'll resize only |
| 416 // back to this width, thus once again placing the last tab under the mouse |
| 417 // cursor. |
| 418 int available_width_for_tabs_; |
| 419 |
| 420 // True if a resize layout animation should be run a short delay after the |
| 421 // mouse exits the TabStrip. |
| 422 bool needs_resize_layout_; |
| 423 |
| 424 // The GtkFixed widget. |
| 425 OwnedWidgetGtk tabstrip_; |
| 426 |
| 427 // The bounds of the tabstrip. |
| 428 gfx::Rect bounds_; |
| 429 |
| 430 // The amount to offset tab backgrounds when we are using an autogenerated |
| 431 // tab background image. |
| 432 int tab_vertical_offset_; |
| 433 |
| 434 // Our model. |
| 435 TabStripModel* model_; |
| 436 |
| 437 // The BrowserWindowGtk containing this tab strip. |
| 438 BrowserWindowGtk* window_; |
| 439 |
| 440 // Theme resources. |
| 441 GtkThemeProvider* theme_provider_; |
| 442 |
| 443 // The currently running animation. |
| 444 scoped_ptr<TabAnimation> active_animation_; |
| 445 |
| 446 // The New Tab button. |
| 447 scoped_ptr<CustomDrawButton> newtab_button_; |
| 448 |
| 449 // Valid for the lifetime of a drag over us. |
| 450 scoped_ptr<DropInfo> drop_info_; |
| 451 |
| 452 // The controller for a drag initiated from a Tab. Valid for the lifetime of |
| 453 // the drag session. |
| 454 scoped_ptr<DraggedTabControllerGtk> drag_controller_; |
| 455 |
| 456 // A factory that is used to construct a delayed callback to the |
| 457 // ResizeLayoutTabsNow method. |
| 458 ScopedRunnableMethodFactory<TabStripGtk> resize_layout_factory_; |
| 459 |
| 460 // True if the tabstrip has already been added as a MessageLoop observer. |
| 461 bool added_as_message_loop_observer_; |
| 462 |
| 463 DISALLOW_COPY_AND_ASSIGN(TabStripGtk); |
| 464 }; |
| 465 |
| 466 #endif // CHROME_BROWSER_UI_GTK_TABS_TAB_STRIP_GTK_H_ |
OLD | NEW |