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