172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/tabs/tab_strip_gtk.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/rtl.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/utf_string_conversions.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/autocomplete/autocomplete.h" 1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/autocomplete/autocomplete_classifier.h" 1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/autocomplete/autocomplete_match.h" 1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/tabs/tab_strip_model_delegate.h" 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/themes/theme_service.h" 184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h" 194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser_navigator.h" 2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/browser_window_gtk.h" 2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/custom_button.h" 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/gtk_theme_service.h" 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h" 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/tabs/dragged_tab_controller_gtk.h" 2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h" 28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_type.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h" 313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/animation_delegate.h" 323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h" 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/dragdrop/gtk_dnd_util.h" 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/gtk_util.h" 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/point.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDefaultAnimationDurationMs = 100; 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kResizeLayoutAnimationDurationMs = 166; 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kReorderAnimationDurationMs = 166; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kAnimateToBoundsDurationMs = 150; 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMiniTabAnimationDurationMs = 150; 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kNewTabButtonHOffset = -5; 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kNewTabButtonVOffset = 5; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The delay between when the mouse leaves the tabstrip and the resize animation 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is started. 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kResizeTabsTimeMs = 300; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The range outside of the tabstrip where the pointer must enter/leave to 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// start/stop the resize animation. 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTabStripAnimationVSlop = 40; 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kHorizontalMoveThreshold = 16; // pixels 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The horizontal offset from one tab to the next, which results in overlapping 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// tabs. 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTabHOffset = -16; 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A linux specific menu item for toggling window decorations. 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kShowWindowDecorationsCommand = 200; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Size of the drop indicator. 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic int drop_indicator_width; 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic int drop_indicator_height; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochinline int Round(double x) { 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return static_cast<int>(x + 0.5); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// widget->allocation is not guaranteed to be set. After window creation, 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we pick up the normal bounds by connecting to the configure-event signal. 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect GetInitialWidgetBounds(GtkWidget* widget) { 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkRequisition request; 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_size_request(widget, &request); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Rect(0, 0, request.width, request.height); 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sort rectangles based on their x position. We don't care about y position 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// so we don't bother breaking ties. 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint CompareGdkRectangles(const void* p1, const void* p2) { 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int p1_x = static_cast<const GdkRectangle*>(p1)->x; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int p2_x = static_cast<const GdkRectangle*>(p2)->x; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (p1_x < p2_x) 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return -1; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (p1_x == p2_x) 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 1; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool GdkRectMatchesTabFaviconBounds(const GdkRectangle& gdk_rect, TabGtk* tab) { 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect favicon_bounds = tab->favicon_bounds(); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gdk_rect.x == favicon_bounds.x() + tab->x() && 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_rect.y == favicon_bounds.y() + tab->y() && 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_rect.width == favicon_bounds.width() && 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_rect.height == favicon_bounds.height(); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabAnimation 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A base class for all TabStrip animations. 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 1103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass TabStripGtk::TabAnimation : public ui::AnimationDelegate { 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch friend class TabStripGtk; 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Possible types of animation. 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch enum Type { 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch INSERT, 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch REMOVE, 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MOVE, 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RESIZE, 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MINI, 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MINI_MOVE 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabAnimation(TabStripGtk* tabstrip, Type type) 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : tabstrip_(tabstrip), 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_(this), 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_selected_width_(0), 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_unselected_width_(0), 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_selected_width_(0), 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_unselected_width_(0), 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout_on_completion_(false), 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch type_(type) { 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~TabAnimation() {} 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Type type() const { return type_; } 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Start() { 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_.SetSlideDuration(GetDuration()); 1403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen animation_.SetTweenType(ui::Tween::EASE_OUT); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!animation_.IsShowing()) { 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_.Reset(); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_.Show(); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Stop() { 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_.Stop(); 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void set_layout_on_completion(bool layout_on_completion) { 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout_on_completion_ = layout_on_completion; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Retrieves the width for the Tab at the specified index if an animation is 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // active. 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static double GetCurrentTabWidth(TabStripGtk* tabstrip, 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripGtk::TabAnimation* animation, 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = tabstrip->GetTabAt(index); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double tab_width; 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) { 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_width = TabGtk::GetMiniWidth(); 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double unselected, selected; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip->GetCurrentTabWidths(&unselected, &selected); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_width = tab->IsSelected() ? selected : unselected; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (animation) { 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double specified_tab_width = animation->GetWidthForTab(index); 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (specified_tab_width != -1) 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_width = specified_tab_width; 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tab_width; 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Overridden from ui::AnimationDelegate: 1803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationProgressed(const ui::Animation* animation) { 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->AnimationLayout(end_unselected_width_); 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationEnded(const ui::Animation* animation) { 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->FinishAnimation(this, layout_on_completion_); 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This object is destroyed now, so we can't do anything else after this. 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1893f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationCanceled(const ui::Animation* animation) { 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AnimationEnded(animation); 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the gap before the tab at the specified index. Subclass if during 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // an animation you need to insert a gap before a tab. 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetGapWidth(int index) { 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the duration of the animation. 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int GetDuration() const { 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return kDefaultAnimationDurationMs; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Subclasses override to return the width of the Tab at the specified index 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // at the current animation frame. -1 indicates the default width should be 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // used for the Tab. 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetWidthForTab(int index) const { 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return -1; // Use default. 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Figure out the desired start and end widths for the specified pre- and 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // post- animation tab counts. 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void GenerateStartAndEndWidths(int start_tab_count, int end_tab_count, 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_mini_count, 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_mini_count) { 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->GetDesiredTabWidths(start_tab_count, start_mini_count, 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &start_unselected_width_, 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &start_selected_width_); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double standard_tab_width = 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(TabRendererGtk::GetStandardSize().width()); 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((end_tab_count - start_tab_count) > 0 && 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_unselected_width_ < standard_tab_width) { 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double minimum_tab_width = static_cast<double>( 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRendererGtk::GetMinimumUnselectedSize().width()); 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_unselected_width_ -= minimum_tab_width / start_tab_count; 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->GenerateIdealBounds(); 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->GetDesiredTabWidths(end_tab_count, end_mini_count, 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &end_unselected_width_, 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &end_selected_width_); 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripGtk* tabstrip_; 2373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen ui::SlideAnimation animation_; 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double start_selected_width_; 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double start_unselected_width_; 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double end_selected_width_; 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double end_unselected_width_; 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // True if a complete re-layout is required upon completion of the animation. 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Subclasses set this if they don't perform a complete layout 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // themselves and canceling the animation may leave the strip in an 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // inconsistent state. 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool layout_on_completion_; 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Type type_; 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(TabAnimation); 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles insertion of a Tab at |index|. 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass InsertTabAnimation : public TabStripGtk::TabAnimation { 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit InsertTabAnimation(TabStripGtk* tabstrip, int index) 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : TabAnimation(tabstrip, INSERT), 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_(index) { 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = tabstrip->GetTabCount(); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_mini_count = tabstrip->GetMiniTabCount(); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_mini_count = end_mini_count; 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index < end_mini_count) 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_mini_count--; 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateStartAndEndWidths(tab_count - 1, tab_count, start_mini_count, 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_mini_count); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~InsertTabAnimation() {} 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from TabStripGtk::TabAnimation: 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetWidthForTab(int index) const { 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == index_) { 278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool is_selected = tabstrip_->model()->active_index() == index; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double start_width, target_width; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index < tabstrip_->GetMiniTabCount()) { 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_width = TabGtk::GetMinimumSelectedSize().width(); 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_width = TabGtk::GetMiniWidth(); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_width = 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_selected ? end_unselected_width_ : end_selected_width_; 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_width = 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_selected ? TabGtk::GetMinimumSelectedSize().width() : 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk::GetMinimumUnselectedSize().width(); 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delta = target_width - start_width; 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (delta > 0) 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return start_width + (delta * animation_.GetCurrentValue()); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return start_width; 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tabstrip_->GetTabAt(index)->mini()) 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TabGtk::GetMiniWidth(); 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tabstrip_->GetTabAt(index)->IsSelected()) { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delta = end_selected_width_ - start_selected_width_; 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return start_selected_width_ + (delta * animation_.GetCurrentValue()); 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delta = end_unselected_width_ - start_unselected_width_; 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return start_unselected_width_ + (delta * animation_.GetCurrentValue()); 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index_; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(InsertTabAnimation); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles removal of a Tab from |index| 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass RemoveTabAnimation : public TabStripGtk::TabAnimation { 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveTabAnimation(TabStripGtk* tabstrip, int index, TabContents* contents) 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : TabAnimation(tabstrip, REMOVE), 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_(index) { 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = tabstrip->GetTabCount(); 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_mini_count = tabstrip->GetMiniTabCount(); 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_mini_count = start_mini_count; 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index < start_mini_count) 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_mini_count--; 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateStartAndEndWidths(tab_count, tab_count - 1, start_mini_count, 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_mini_count); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the last non-mini-tab is being removed we force a layout on 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // completion. This is necessary as the value returned by GetTabHOffset 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // changes once the tab is actually removed (which happens at the end of 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the animation), and unless we layout GetTabHOffset won't be called after 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the removal. 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We do the same when the last mini-tab is being removed for the same 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // reason. 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_layout_on_completion(start_mini_count > 0 && 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (end_mini_count == 0 || 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (start_mini_count == end_mini_count && 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_count == start_mini_count + 1))); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~RemoveTabAnimation() {} 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the index of the tab being removed. 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index() const { return index_; } 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from TabStripGtk::TabAnimation: 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetWidthForTab(int index) const { 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = tabstrip_->GetTabAt(index); 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == index_) { 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The tab(s) being removed are gradually shrunken depending on the state 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of the animation. 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) { 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(TabGtk::GetMiniWidth(), 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch -kTabHOffset); 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Removed animated Tabs are never selected. 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double start_width = start_unselected_width_; 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure target_width is at least abs(kTabHOffset), otherwise if 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // less than kTabHOffset during layout tabs get negatively offset. 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double target_width = 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::max(abs(kTabHOffset), 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk::GetMinimumUnselectedSize().width() + kTabHOffset); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_width, target_width); 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TabGtk::GetMiniWidth(); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tabstrip_->available_width_for_tabs_ != -1 && 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_ != tabstrip_->GetTabCount() - 1) { 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TabStripGtk::TabAnimation::GetWidthForTab(index); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // All other tabs are sized according to the start/end widths specified at 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the start of the animation. 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->IsSelected()) { 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delta = end_selected_width_ - start_selected_width_; 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return start_selected_width_ + (delta * animation_.GetCurrentValue()); 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delta = end_unselected_width_ - start_unselected_width_; 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return start_unselected_width_ + (delta * animation_.GetCurrentValue()); 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3913f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationEnded(const ui::Animation* animation) { 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->RemoveTabAt(index_); 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripGtk::TabAnimation::AnimationEnded(animation); 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index_; 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(RemoveTabAnimation); 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles the movement of a Tab from one position to another. 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MoveTabAnimation : public TabStripGtk::TabAnimation { 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MoveTabAnimation(TabStripGtk* tabstrip, int tab_a_index, int tab_b_index) 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : TabAnimation(tabstrip, MOVE), 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_tab_a_bounds_(tabstrip_->GetIdealBounds(tab_b_index)), 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_tab_b_bounds_(tabstrip_->GetIdealBounds(tab_a_index)) { 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_a_ = tabstrip_->GetTabAt(tab_a_index); 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_b_ = tabstrip_->GetTabAt(tab_b_index); 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Since we don't do a full TabStrip re-layout, we need to force a full 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // layout upon completion since we're not guaranteed to be in a good state 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // if for example the animation is canceled. 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_layout_on_completion(true); 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~MoveTabAnimation() {} 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Overridden from ui::AnimationDelegate: 4223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationProgressed(const ui::Animation* animation) { 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Position Tab A 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double distance = start_tab_b_bounds_.x() - start_tab_a_bounds_.x(); 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delta = distance * animation_.GetCurrentValue(); 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double new_x = start_tab_a_bounds_.x() + delta; 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds(Round(new_x), start_tab_a_bounds_.y(), tab_a_->width(), 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_a_->height()); 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->SetTabBounds(tab_a_, bounds); 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Position Tab B 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch distance = start_tab_a_bounds_.x() - start_tab_b_bounds_.x(); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delta = distance * animation_.GetCurrentValue(); 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_x = start_tab_b_bounds_.x() + delta; 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds = gfx::Rect(Round(new_x), start_tab_b_bounds_.y(), tab_b_->width(), 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_b_->height()); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->SetTabBounds(tab_b_, bounds); 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from TabStripGtk::TabAnimation: 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int GetDuration() const { return kReorderAnimationDurationMs; } 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The two tabs being exchanged. 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab_a_; 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab_b_; 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // ...and their bounds. 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect start_tab_a_bounds_; 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect start_tab_b_bounds_; 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(MoveTabAnimation); 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles the animated resize layout of the entire TabStrip from one width 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to another. 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ResizeLayoutAnimation : public TabStripGtk::TabAnimation { 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit ResizeLayoutAnimation(TabStripGtk* tabstrip) 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : TabAnimation(tabstrip, RESIZE) { 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = tabstrip->GetTabCount(); 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int mini_tab_count = tabstrip->GetMiniTabCount(); 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateStartAndEndWidths(tab_count, tab_count, mini_tab_count, 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mini_tab_count); 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InitStartState(); 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~ResizeLayoutAnimation() {} 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Overridden from ui::AnimationDelegate: 4733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationEnded(const ui::Animation* animation) { 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->needs_resize_layout_ = false; 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripGtk::TabAnimation::AnimationEnded(animation); 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from TabStripGtk::TabAnimation: 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int GetDuration() const { 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return kResizeLayoutAnimationDurationMs; 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetWidthForTab(int index) const { 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = tabstrip_->GetTabAt(index); 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TabGtk::GetMiniWidth(); 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->IsSelected()) { 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_selected_width_, 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_selected_width_); 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_unselected_width_, 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_unselected_width_); 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to start from the current widths of the Tabs as they were last 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // laid out, _not_ the last known good state, which is what'll be done if we 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // don't measure the Tab sizes here and just go with the default TabAnimation 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // behavior... 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void InitStartState() { 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < tabstrip_->GetTabCount(); ++i) { 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* current_tab = tabstrip_->GetTabAt(i); 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!current_tab->mini()) { 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_tab->IsSelected()) { 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_selected_width_ = current_tab->width(); 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_unselected_width_ = current_tab->width(); 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(ResizeLayoutAnimation); 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles a tabs mini-state changing while the tab does not change position 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// in the model. 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MiniTabAnimation : public TabStripGtk::TabAnimation { 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit MiniTabAnimation(TabStripGtk* tabstrip, int index) 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : TabAnimation(tabstrip, MINI), 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index_(index) { 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = tabstrip->GetTabCount(); 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_mini_count = tabstrip->GetMiniTabCount(); 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_mini_count = start_mini_count; 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tabstrip->GetTabAt(index)->mini()) 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_mini_count--; 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_mini_count++; 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->GetTabAt(index)->set_animating_mini_change(true); 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateStartAndEndWidths(tab_count, tab_count, start_mini_count, 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_mini_count); 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from TabStripGtk::TabAnimation: 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int GetDuration() const { 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return kMiniTabAnimationDurationMs; 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetWidthForTab(int index) const { 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = tabstrip_->GetTabAt(index); 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == index_) { 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) { 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween( 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_selected_width_, 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(TabGtk::GetMiniWidth())); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween( 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(TabGtk::GetMiniWidth()), 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_selected_width_); 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (tab->mini()) { 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TabGtk::GetMiniWidth(); 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->IsSelected()) { 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_selected_width_, 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_selected_width_); 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_unselected_width_, 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_unselected_width_); 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Index of the tab whose mini-state changed. 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index_; 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(MiniTabAnimation); 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Handles the animation when a tabs mini-state changes and the tab moves as a 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// result. 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MiniMoveAnimation : public TabStripGtk::TabAnimation { 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit MiniMoveAnimation(TabStripGtk* tabstrip, 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int from_index, 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int to_index, 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& start_bounds) 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : TabAnimation(tabstrip, MINI_MOVE), 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_(tabstrip->GetTabAt(to_index)), 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_bounds_(start_bounds), 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch from_index_(from_index), 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch to_index_(to_index) { 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = tabstrip->GetTabCount(); 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_mini_count = tabstrip->GetMiniTabCount(); 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_mini_count = start_mini_count; 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tabstrip->GetTabAt(to_index)->mini()) 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_mini_count--; 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_mini_count++; 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateStartAndEndWidths(tab_count, tab_count, start_mini_count, 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_mini_count); 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_bounds_ = tabstrip->GetIdealBounds(to_index); 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_->set_animating_mini_change(true); 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6063f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen // Overridden from ui::AnimationDelegate: 6073f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationProgressed(const ui::Animation* animation) { 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Do the normal layout. 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabAnimation::AnimationProgressed(animation); 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Then special case the position of the tab being moved. 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int x = animation_.CurrentValueBetween(start_bounds_.x(), 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_bounds_.x()); 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int width = animation_.CurrentValueBetween(start_bounds_.width(), 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_bounds_.width()); 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect tab_bounds(x, start_bounds_.y(), width, 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch start_bounds_.height()); 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->SetTabBounds(tab_, tab_bounds); 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen virtual void AnimationEnded(const ui::Animation* animation) { 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_->needs_resize_layout_ = false; 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripGtk::TabAnimation::AnimationEnded(animation); 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetGapWidth(int index) { 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (to_index_ < from_index_) { 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The tab was made mini. 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == to_index_) { 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double current_size = 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_.CurrentValueBetween(0, target_bounds_.width()); 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_size < -kTabHOffset) 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return -(current_size + kTabHOffset); 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (index == from_index_ + 1) { 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_bounds_.width(), 0); 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The tab was was made a normal tab. 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == from_index_) { 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween( 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk::GetMiniWidth() + kTabHOffset, 0); 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Overridden from TabStripGtk::TabAnimation: 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int GetDuration() const { return kReorderAnimationDurationMs; } 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual double GetWidthForTab(int index) const { 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = tabstrip_->GetTabAt(index); 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index == to_index_) 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(0, target_bounds_.width()); 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TabGtk::GetMiniWidth(); 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->IsSelected()) { 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_selected_width_, 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_selected_width_); 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return animation_.CurrentValueBetween(start_unselected_width_, 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end_unselected_width_); 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The tab being moved. 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab_; 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initial bounds of tab_. 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect start_bounds_; 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Target bounds. 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect target_bounds_; 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start and end indices of the tab. 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int from_index_; 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int to_index_; 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(MiniMoveAnimation); 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabStripGtk, public: 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int TabStripGtk::mini_to_non_mini_gap_ = 3; 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabStripGtk::TabStripGtk(TabStripModel* model, BrowserWindowGtk* window) 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : current_unselected_width_(TabGtk::GetStandardSize().width()), 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_selected_width_(TabGtk::GetStandardSize().width()), 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width_for_tabs_(-1), 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch needs_resize_layout_(false), 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_vertical_offset_(0), 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_(model), 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch window_(window), 700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen theme_service_(GtkThemeService::GetFrom(model->profile())), 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_layout_factory_(this), 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch added_as_message_loop_observer_(false) { 703ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen theme_service_->InitThemesFor(this); 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabStripGtk::~TabStripGtk() { 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->RemoveObserver(this); 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_.Destroy(); 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Free any remaining tabs. This is needed to free the very last tab, 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because it is not animated on close. This also happens when all of the 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tabs are closed at once. 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<TabData>::iterator iterator = tab_data_.begin(); 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; iterator < tab_data_.end(); iterator++) { 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete iterator->tab; 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.clear(); 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure we unhook ourselves as a message loop observer so that we don't 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // crash in the case where the user closes the last tab in a window. 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveMessageLoopObserver(); 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::Init() { 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->AddObserver(this); 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabstrip_.Own(gtk_fixed_new()); 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ViewIDUtil::SetID(tabstrip_.get(), VIEW_ID_TAB_STRIP); 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We want the tab strip to be horizontally shrinkable, so that the Chrome 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // window can be resized freely. 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_size_request(tabstrip_.get(), 0, 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk::GetMinimumUnselectedSize().height()); 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_app_paintable(tabstrip_.get(), TRUE); 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_drag_dest_set(tabstrip_.get(), GTK_DEST_DEFAULT_ALL, 738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 0, 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<GdkDragAction>( 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK)); 74172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen static const int targets[] = { ui::TEXT_URI_LIST, 74272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::NETSCAPE_URL, 74372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::TEXT_PLAIN, 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch -1 }; 74572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::SetDestTargetList(tabstrip_.get(), targets); 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(tabstrip_.get(), "expose-event", 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnExposeThunk), this); 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(tabstrip_.get(), "size-allocate", 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnSizeAllocateThunk), this); 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(tabstrip_.get(), "drag-motion", 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragMotionThunk), this); 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(tabstrip_.get(), "drag-drop", 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragDropThunk), this); 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(tabstrip_.get(), "drag-leave", 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragLeaveThunk), this); 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(tabstrip_.get(), "drag-data-received", 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragDataReceivedThunk), this); 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch newtab_button_.reset(MakeNewTabButton()); 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_show_all(tabstrip_.get()); 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds_ = GetInitialWidgetBounds(tabstrip_.get()); 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drop_indicator_width == 0) { 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Direction doesn't matter, both images are the same size. 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkPixbuf* drop_image = GetDropArrowImage(true); 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_width = gdk_pixbuf_get_width(drop_image); 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_height = gdk_pixbuf_get_height(drop_image); 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ViewIDUtil::SetDelegateForWidget(widget(), this); 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::Show() { 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_show(tabstrip_.get()); 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::Hide() { 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_hide(tabstrip_.get()); 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 78421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TabStripGtk::IsActiveDropTarget() const { 78521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen for (int i = 0; i < GetTabCount(); ++i) { 78621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen TabGtk* tab = GetTabAt(i); 78721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (tab->dragging()) 78821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return true; 78921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 79021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 79121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 79221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::Layout() { 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Called from: 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // - window resize 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // - animation completion 797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateIdealBounds(); 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = GetTabCount(); 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_right = 0; 802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < tab_count; ++i) { 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& bounds = tab_data_.at(i).ideal_bounds; 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(i); 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->set_animating_mini_change(false); 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->set_vertical_offset(tab_vertical_offset_); 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetTabBounds(tab, bounds); 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_right = bounds.right(); 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_right += GetTabHOffset(i + 1); 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LayoutNewTabButton(static_cast<double>(tab_right), current_unselected_width_); 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::SchedulePaint() { 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_queue_draw(tabstrip_.get()); 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::SetBounds(const gfx::Rect& bounds) { 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds_ = bounds; 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::UpdateLoadingAnimations() { 824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0, index = 0; i < GetTabCount(); ++i, ++index) { 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* current_tab = GetTabAt(i); 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_tab->closing()) { 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch --index; 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabRendererGtk::AnimationState state; 830201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch TabContentsWrapper* contents = model_->GetTabContentsAt(index); 831201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (!contents || !contents->tab_contents()->is_loading()) { 832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch state = TabGtk::ANIMATION_NONE; 833201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } else if (contents->tab_contents()->waiting_for_response()) { 834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch state = TabGtk::ANIMATION_WAITING; 835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch state = TabGtk::ANIMATION_LOADING; 837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_tab->ValidateLoadingAnimation(state)) { 839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Queue the tab's icon area to be repainted. 840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect favicon_bounds = current_tab->favicon_bounds(); 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_queue_draw_area(tabstrip_.get(), 842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_bounds.x() + current_tab->x(), 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_bounds.y() + current_tab->y(), 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_bounds.width(), 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch favicon_bounds.height()); 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsCompatibleWith(TabStripGtk* other) { 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return model_->profile() == other->model()->profile(); 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsAnimating() const { 856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return active_animation_.get() != NULL; 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DestroyDragController() { 860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_controller_.reset(); 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DestroyDraggedSourceTab(TabGtk* tab) { 864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We could be running an animation that references this Tab. 865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure we leave the tab_data_ vector in a consistent state, otherwise 868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we'll be pointing to tabs that have been deleted and removed from the 869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // child view list. 870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<TabData>::iterator it = tab_data_.begin(); 871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; it != tab_data_.end(); ++it) { 872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it->tab == tab) { 873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!model_->closing_all()) 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Leaving in an inconsistent state!"; 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.erase(it); 876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_remove(GTK_CONTAINER(tabstrip_.get()), tab->widget()); 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we delete the dragged source tab here, the DestroyDragWidget posted 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // task will be run after the tab is deleted, leading to a crash. 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->DeleteSoon(FROM_HERE, tab); 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Force a layout here, because if we've just quickly drag detached a Tab, 886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the stopping of the active animation above may have left the TabStrip in a 887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bad (visual) state. 888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect TabStripGtk::GetIdealBounds(int index) { 892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(index >= 0 && index < GetTabCount()); 893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tab_data_.at(index).ideal_bounds; 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::SetVerticalOffset(int offset) { 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_vertical_offset_ = offset; 898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Point TabStripGtk::GetTabStripOriginForWidget(GtkWidget* target) { 902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int x, y; 903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!gtk_widget_translate_coordinates(widget(), target, 904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch -widget()->allocation.x, 0, &x, &y)) { 905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the tab strip isn't showing, give the coordinates relative to the 906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // toplevel instead. 907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!gtk_widget_translate_coordinates( 908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_get_toplevel(widget()), target, 0, 0, &x, &y)) { 909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GTK_WIDGET_NO_WINDOW(target)) { 913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch x += target->allocation.x; 914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y += target->allocation.y; 915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Point(x, y); 917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ViewIDUtil::Delegate implementation 921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 922c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGtkWidget* TabStripGtk::GetWidgetForViewID(ViewID view_id) { 923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetTabCount() > 0) { 924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (view_id == VIEW_ID_TAB_LAST) { 925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetTabAt(GetTabCount() - 1)->widget(); 926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { 927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index = view_id - VIEW_ID_TAB_0; 928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (index >= 0 && index < GetTabCount()) { 929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetTabAt(index)->widget(); 930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabStripGtk, TabStripModelObserver implementation: 941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 942201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabInsertedAt(TabContentsWrapper* contents, 943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool foreground) { 945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(contents); 946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(index == TabStripModel::kNoTab || model_->ContainsIndex(index)); 947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool contains_tab = false; 951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = NULL; 952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First see if this Tab is one that was dragged out of this TabStrip and is 953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // now being dragged back in. In this case, the DraggedTabController actually 954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // has the Tab already constructed and we can just insert it into our list 955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // again. 956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsDragSessionActive()) { 957201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch tab = drag_controller_->GetDragSourceTabForContents( 958201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch contents->tab_contents()); 959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab) { 960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the Tab was detached, it would have been animated closed but not 961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // removed, so we need to reset this property. 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->set_closing(false); 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->ValidateLoadingAnimation(TabRendererGtk::ANIMATION_NONE); 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->SetVisible(true); 965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See if we're already in the list. We don't want to add ourselves twice. 968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<TabData>::const_iterator iter = tab_data_.begin(); 969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (; iter != tab_data_.end() && !contains_tab; ++iter) { 970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (iter->tab == tab) 971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch contains_tab = true; 972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!tab) 976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab = new TabGtk(this); 977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only insert if we're not already in the list. 979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!contains_tab) { 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabData d = { tab, gfx::Rect() }; 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.insert(tab_data_.begin() + index, d); 982201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch tab->UpdateData(contents->tab_contents(), model_->IsAppTab(index), false); 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->set_mini(model_->IsMiniTab(index)); 985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->set_app(model_->IsAppTab(index)); 986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->SetBlocked(model_->IsTabBlocked(index)); 987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (gtk_widget_get_parent(tab->widget()) != tabstrip_.get()) 989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_fixed_put(GTK_FIXED(tabstrip_.get()), tab->widget(), 0, 0); 990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't animate the first tab; it looks weird. 992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetTabCount() > 1) { 993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartInsertTabAnimation(index); 994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We added the tab at 0x0, we need to force an animation step otherwise 995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // if GTK paints before the animation event the tab is painted at 0x0 996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which is most likely not where it should be positioned. 997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->AnimationProgressed(NULL); 998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1003201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabDetachedAt(TabContentsWrapper* contents, int index) { 1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateIdealBounds(); 1005201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch StartRemoveTabAnimation(index, contents->tab_contents()); 1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Have to do this _after_ calling StartRemoveTabAnimation, so that any 1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // previous remove is completed fully and index is valid in sync with the 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // model index. 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(index)->set_closing(true); 1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1012201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabSelectedAt(TabContentsWrapper* old_contents, 1013201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch TabContentsWrapper* new_contents, 1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, 1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool user_gesture) { 1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(index >= 0 && index < static_cast<int>(GetTabCount())); 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We have "tiny tabs" if the tabs are so tiny that the unselected ones are 1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a different size to the selected ones. 1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool tiny_tabs = current_unselected_width_ != current_selected_width_; 1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsAnimating() && (!needs_resize_layout_ || tiny_tabs)) 1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(index)->SchedulePaint(); 1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int old_index = model_->GetIndexOfTabContents(old_contents); 1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (old_index >= 0) { 1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(old_index)->SchedulePaint(); 1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(old_index)->StopMiniTabTitleAnimation(); 1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1033201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabMoved(TabContentsWrapper* contents, 1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int from_index, 1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int to_index) { 1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect start_bounds = GetIdealBounds(from_index); 1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(from_index); 1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.erase(tab_data_.begin() + from_index); 1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabData data = {tab, gfx::Rect()}; 1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->set_mini(model_->IsMiniTab(to_index)); 1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->SetBlocked(model_->IsTabBlocked(to_index)); 1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.insert(tab_data_.begin() + to_index, data); 1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GenerateIdealBounds(); 1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartMoveTabAnimation(from_index, to_index); 1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1047201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabChangedAt(TabContentsWrapper* contents, int index, 1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabChangeType change_type) { 1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Index is in terms of the model. Need to make sure we adjust that index in 1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // case we have an animation going. 1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAtAdjustForAnimation(index); 1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (change_type == TITLE_NOT_LOADING) { 1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini() && !tab->IsSelected()) 1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->StartMiniTabTitleAnimation(); 1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We'll receive another notification of the change asynchronously. 1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1058201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch tab->UpdateData(contents->tab_contents(), 1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->IsAppTab(index), 1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch change_type == LOADING_ONLY); 1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->UpdateFromModel(); 1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 106472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid TabStripGtk::TabReplacedAt(TabStripModel* tab_strip_model, 106572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TabContentsWrapper* old_contents, 1066201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch TabContentsWrapper* new_contents, 1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index) { 1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabChangedAt(new_contents, index, ALL); 1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1071201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabMiniStateChanged(TabContentsWrapper* contents, int index) { 1072513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Don't do anything if we've already picked up the change from TabMoved. 1073513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (GetTabAt(index)->mini() == model_->IsMiniTab(index)) 1074513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return; 1075513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(index)->set_mini(model_->IsMiniTab(index)); 1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't animate if the window isn't visible yet. The window won't be visible 1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // when dragging a mini-tab to a new window. 1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (window_ && window_->window() && 1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GTK_WIDGET_VISIBLE(GTK_WIDGET(window_->window()))) { 1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartMiniTabAnimation(index); 1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1087201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TabStripGtk::TabBlockedStateChanged(TabContentsWrapper* contents, 1088201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch int index) { 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(index)->SetBlocked(model_->IsTabBlocked(index)); 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabStripGtk, TabGtk::TabDelegate implementation: 1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsTabSelected(const TabGtk* tab) const { 1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->closing()) 1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1099ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return GetIndexOfTab(tab) == model_->active_index(); 1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsTabDetached(const TabGtk* tab) const { 1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drag_controller_.get()) 1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return drag_controller_->IsTabDetached(tab); 1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::GetCurrentTabWidths(double* unselected_width, 1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double* selected_width) const { 1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *unselected_width = current_unselected_width_; 1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *selected_width = current_selected_width_; 1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsTabPinned(const TabGtk* tab) const { 1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->closing()) 1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return model_->IsTabPinned(GetIndexOfTab(tab)); 1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::SelectTab(TabGtk* tab) { 1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index = GetIndexOfTab(tab); 1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (model_->ContainsIndex(index)) 1124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen model_->ActivateTabAt(index, true); 1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::CloseTab(TabGtk* tab) { 1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_index = GetIndexOfTab(tab); 1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (model_->ContainsIndex(tab_index)) { 1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* last_tab = GetTabAt(GetTabCount() - 1); 1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Limit the width available to the TabStrip for laying out Tabs, so that 1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Tabs are not resized until a later time (when the mouse pointer leaves 1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the TabStrip). 1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); 1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch needs_resize_layout_ = true; 1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We hook into the message loop in order to receive mouse move events when 1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the mouse is outside of the tabstrip. We unhook once the resize layout 1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // animation is started. 1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddMessageLoopObserver(); 1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->CloseTabContentsAt(tab_index, 1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripModel::CLOSE_USER_GESTURE | 1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); 1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsCommandEnabledForTab( 1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripModel::ContextMenuCommand command_id, const TabGtk* tab) const { 1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index = GetIndexOfTab(tab); 1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (model_->ContainsIndex(index)) 1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return model_->IsContextMenuCommandEnabled(index, command_id); 1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::ExecuteCommandForTab( 1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripModel::ContextMenuCommand command_id, TabGtk* tab) { 1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index = GetIndexOfTab(tab); 1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (model_->ContainsIndex(index)) 1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->ExecuteContextMenuCommand(index, command_id); 1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartHighlightTabsForCommand( 1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripModel::ContextMenuCommand command_id, TabGtk* tab) { 1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (command_id == TabStripModel::CommandCloseOtherTabs || 1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command_id == TabStripModel::CommandCloseTabsToRight) { 1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTIMPLEMENTED(); 1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StopHighlightTabsForCommand( 1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabStripModel::ContextMenuCommand command_id, TabGtk* tab) { 1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (command_id == TabStripModel::CommandCloseTabsToRight || 1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch command_id == TabStripModel::CommandCloseOtherTabs) { 1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Just tell all Tabs to stop pulsing - it's safe. 1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAllHighlighting(); 1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StopAllHighlighting() { 1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(jhawkins): Hook up animations. 1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTIMPLEMENTED(); 1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::MaybeStartDrag(TabGtk* tab, const gfx::Point& point) { 1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't accidentally start any drag operations during animations if the 1185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // mouse is down. 1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (IsAnimating() || tab->closing() || !HasAvailableDragActions()) 1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_controller_.reset(new DraggedTabControllerGtk(tab, this)); 1190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_controller_->CaptureDragInfo(point); 1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::ContinueDrag(GdkDragContext* context) { 1194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can get called even if |MaybeStartDrag| wasn't called in the event of 1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a TabStrip animation when the mouse button is down. In this case we should 1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // _not_ continue the drag because it can lead to weird bugs. 1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drag_controller_.get()) 1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_controller_->Drag(); 1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::EndDrag(bool canceled) { 1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return drag_controller_.get() ? drag_controller_->EndDrag(canceled) : false; 1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::HasAvailableDragActions() const { 1206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return model_->delegate()->GetDragActions() != 0; 1207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenui::ThemeProvider* TabStripGtk::GetThemeProvider() { 1210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return theme_service_; 1211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/////////////////////////////////////////////////////////////////////////////// 1214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabStripGtk, MessageLoop::Observer implementation: 1215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::WillProcessEvent(GdkEvent* event) { 1217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Nothing to do. 1218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DidProcessEvent(GdkEvent* event) { 1221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (event->type) { 1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case GDK_MOTION_NOTIFY: 1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case GDK_LEAVE_NOTIFY: 1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HandleGlobalMouseMoveEvent(); 1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 123172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen/////////////////////////////////////////////////////////////////////////////// 123272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// TabStripGtk, NotificationObserver implementation: 123372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::Observe(NotificationType type, 1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == NotificationType::BROWSER_THEME_CHANGED) { 1238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRendererGtk::SetSelectedTitleColor(theme_service_->GetColor( 1239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ThemeService::COLOR_TAB_TEXT)); 1240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabRendererGtk::SetUnselectedTitleColor(theme_service_->GetColor( 1241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ThemeService::COLOR_BACKGROUND_TAB_TEXT)); 1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabStripGtk, private: 1247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabStripGtk::GetTabCount() const { 1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return static_cast<int>(tab_data_.size()); 1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabStripGtk::GetMiniTabCount() const { 1253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int mini_count = 0; 1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < tab_data_.size(); ++i) { 1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_data_[i].tab->mini()) 1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mini_count++; 1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return mini_count; 1259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return mini_count; 1261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabStripGtk::GetAvailableWidthForTabs(TabGtk* last_tab) const { 1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!base::i18n::IsRTL()) 1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return last_tab->x() - bounds_.x() + last_tab->width(); 1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 1267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return bounds_.width() - last_tab->x(); 1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabStripGtk::GetIndexOfTab(const TabGtk* tab) const { 1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0, index = 0; i < GetTabCount(); ++i, ++index) { 1272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* current_tab = GetTabAt(i); 1273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_tab->closing()) { 1274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch --index; 1275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (current_tab == tab) { 1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return index; 1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return -1; 1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabGtk* TabStripGtk::GetTabAt(int index) const { 1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_GE(index, 0); 1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_LT(index, GetTabCount()); 1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tab_data_.at(index).tab; 1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabGtk* TabStripGtk::GetTabAtAdjustForAnimation(int index) const { 1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (active_animation_.get() && 1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->type() == TabAnimation::REMOVE && 1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index >= 1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<RemoveTabAnimation*>(active_animation_.get())->index()) { 1293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch index++; 1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetTabAt(index); 1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::RemoveTabAt(int index) { 1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* removed = tab_data_.at(index).tab; 1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remove the Tab from the TabStrip's list. 1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.erase(tab_data_.begin() + index); 1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsDragSessionActive() || !drag_controller_->IsDragSourceTab(removed)) { 1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_remove(GTK_CONTAINER(tabstrip_.get()), removed->widget()); 1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete removed; 1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::HandleGlobalMouseMoveEvent() { 1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsCursorInTabStripZone()) { 1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Mouse moved outside the tab slop zone, start a timer to do a resize 1313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // layout after a short while... 1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (resize_layout_factory_.empty()) { 1315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostDelayedTask(FROM_HERE, 1316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_layout_factory_.NewRunnableMethod( 1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &TabStripGtk::ResizeLayoutTabs), 1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kResizeTabsTimeMs); 1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Mouse moved quickly out of the tab strip and then into it again, so 1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // cancel the timer so that the strip doesn't move when the mouse moves 1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // back over it. 1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_layout_factory_.RevokeAll(); 1325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::GenerateIdealBounds() { 1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = GetTabCount(); 1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double unselected, selected; 1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetDesiredTabWidths(tab_count, GetMiniTabCount(), &unselected, &selected); 1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_unselected_width_ = unselected; 1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_selected_width_ = selected; 1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // NOTE: This currently assumes a tab's height doesn't differ based on 1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // selected state or the number of tabs in the strip! 1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_height = TabGtk::GetStandardSize().height(); 1339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double tab_x = tab_start_x(); 1340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < tab_count; ++i) { 1341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(i); 1342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double tab_width = unselected; 1343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab->mini()) 1344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_width = TabGtk::GetMiniWidth(); 1345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (tab->IsSelected()) 1346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_width = selected; 1347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double end_of_tab = tab_x + tab_width; 1348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int rounded_tab_x = Round(tab_x); 1349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect state(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, 1350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_height); 1351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_data_.at(i).ideal_bounds = state; 1352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_x = end_of_tab + GetTabHOffset(i + 1); 1353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::LayoutNewTabButton(double last_tab_right, 1357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double unselected_width) { 1358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds(0, kNewTabButtonVOffset, 1359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch newtab_button_->width(), newtab_button_->height()); 1360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int delta = abs(Round(unselected_width) - TabGtk::GetStandardSize().width()); 1361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (delta > 1 && !needs_resize_layout_) { 1362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We're shrinking tabs, so we need to anchor the New Tab button to the 1363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // right edge of the TabStrip's bounds, rather than the right edge of the 1364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // right-most Tab, otherwise it'll bounce when animating. 1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds.set_x(bounds_.width() - newtab_button_->width()); 1366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds.set_x(Round(last_tab_right - kTabHOffset) + kNewTabButtonHOffset); 1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds.set_x(gtk_util::MirroredLeftPointForRect(tabstrip_.get(), bounds)); 1370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_fixed_move(GTK_FIXED(tabstrip_.get()), newtab_button_->widget(), 1372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds.x(), bounds.y()); 1373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::GetDesiredTabWidths(int tab_count, 1376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int mini_tab_count, 1377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double* unselected_width, 1378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double* selected_width) const { 1379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(tab_count >= 0 && mini_tab_count >= 0 && mini_tab_count <= tab_count); 1380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const double min_unselected_width = 1381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk::GetMinimumUnselectedSize().width(); 1382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const double min_selected_width = 1383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk::GetMinimumSelectedSize().width(); 1384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *unselected_width = min_unselected_width; 1386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *selected_width = min_selected_width; 1387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_count == 0) { 1389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Return immediately to avoid divide-by-zero below. 1390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Determine how much space we can actually allocate to tabs. 1394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int available_width = tabstrip_->allocation.width; 1395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (available_width_for_tabs_ < 0) { 1396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width = bounds_.width(); 1397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width -= 1398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (kNewTabButtonHOffset + newtab_button_->width()); 1399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Interesting corner case: if |available_width_for_tabs_| > the result 1401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of the calculation in the conditional arm above, the strip is in 1402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // overflow. We can either use the specified width or the true available 1403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // width here; the first preserves the consistent "leave the last tab under 1404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the user's mouse so they can close many tabs" behavior at the cost of 1405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // prolonging the glitchy appearance of the overflow state, while the second 1406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // gets us out of overflow as soon as possible but forces the user to move 1407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // their mouse for a few tabs' worth of closing. We choose visual 1408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // imperfection over behavioral imperfection and select the first option. 1409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width = available_width_for_tabs_; 1410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (mini_tab_count > 0) { 1413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width -= mini_tab_count * (TabGtk::GetMiniWidth() + kTabHOffset); 1414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_count -= mini_tab_count; 1415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_count == 0) { 1416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *selected_width = *unselected_width = TabGtk::GetStandardSize().width(); 1417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Account for gap between the last mini-tab and first normal tab. 1420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width -= mini_to_non_mini_gap_; 1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Calculate the desired tab widths by dividing the available space into equal 1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // portions. Don't let tabs get larger than the "standard width" or smaller 1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // than the minimum width for each type, respectively. 1426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int total_offset = kTabHOffset * (tab_count - 1); 1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const double desired_tab_width = std::min( 1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (static_cast<double>(available_width - total_offset) / 1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(tab_count)), 1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(TabGtk::GetStandardSize().width())); 1431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *unselected_width = std::max(desired_tab_width, min_unselected_width); 1433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *selected_width = std::max(desired_tab_width, min_selected_width); 1434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When there are multiple tabs, we'll have one selected and some unselected 1436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tabs. If the desired width was between the minimum sizes of these types, 1437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // try to shrink the tabs with the smaller minimum. For example, if we have 1438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a strip of width 10 with 4 tabs, the desired width per tab will be 2.5. If 1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // selected tabs have a minimum width of 4 and unselected tabs have a minimum 1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // width of 1, the above code would set *unselected_width = 2.5, 1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // *selected_width = 4, which results in a total width of 11.5. Instead, we 1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // want to set *unselected_width = 2, *selected_width = 4, for a total width 1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of 10. 1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_count > 1) { 1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ((min_unselected_width < min_selected_width) && 1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (desired_tab_width < min_selected_width)) { 1447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double calc_width = 1448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>( 1449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width - total_offset - min_selected_width) / 1450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(tab_count - 1); 1451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *unselected_width = std::max(calc_width, min_unselected_width); 1452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if ((min_unselected_width > min_selected_width) && 1453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (desired_tab_width < min_unselected_width)) { 1454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *selected_width = std::max(available_width - total_offset - 1455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (min_unselected_width * (tab_count - 1)), min_selected_width); 1456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabStripGtk::GetTabHOffset(int tab_index) { 1461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_index < GetTabCount() && GetTabAt(tab_index - 1)->mini() && 1462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !GetTabAt(tab_index)->mini()) { 1463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return mini_to_non_mini_gap_ + kTabHOffset; 1464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return kTabHOffset; 1466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabStripGtk::tab_start_x() const { 1469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 1470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool TabStripGtk::ResizeLayoutTabs() { 1473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch resize_layout_factory_.RevokeAll(); 1474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It is critically important that this is unhooked here, otherwise we will 1476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // keep spying on messages forever. 1477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RemoveMessageLoopObserver(); 1478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width_for_tabs_ = -1; 1480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int mini_tab_count = GetMiniTabCount(); 1481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (mini_tab_count == GetTabCount()) { 1482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only mini tabs, we know the tab widths won't have changed (all mini-tabs 1483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // have the same width), so there is nothing to do. 14843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 1485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* first_tab = GetTabAt(mini_tab_count); 1487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double unselected, selected; 1488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetDesiredTabWidths(GetTabCount(), mini_tab_count, &unselected, &selected); 1489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int w = Round(first_tab->IsSelected() ? selected : unselected); 1490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We only want to run the animation if we're not already at the desired 1492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // size. 14933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (abs(first_tab->width() - w) > 1) { 1494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartResizeLayoutAnimation(); 14953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 14963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 14973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 14983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 1499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabStripGtk::IsCursorInTabStripZone() const { 1502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point tabstrip_topleft; 1503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_util::ConvertWidgetPointToScreen(tabstrip_.get(), &tabstrip_topleft); 1504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bds = bounds(); 1506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bds.set_origin(tabstrip_topleft); 1507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bds.set_height(bds.height() + kTabStripAnimationVSlop); 1508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkScreen* screen = gdk_screen_get_default(); 1510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkDisplay* display = gdk_screen_get_display(screen); 1511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gint x, y; 1512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_display_get_pointer(display, NULL, &x, &y, NULL); 1513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point cursor_point(x, y); 1514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return bds.Contains(cursor_point); 1516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::AddMessageLoopObserver() { 1519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!added_as_message_loop_observer_) { 1520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->AddObserver(this); 1521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch added_as_message_loop_observer_ = true; 1522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::RemoveMessageLoopObserver() { 1526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (added_as_message_loop_observer_) { 1527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->RemoveObserver(this); 1528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch added_as_message_loop_observer_ = false; 1529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect TabStripGtk::GetDropBounds(int drop_index, 1533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool drop_before, 1534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool* is_beneath) { 1535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_NE(drop_index, -1); 1536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int center_x; 1537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drop_index < GetTabCount()) { 1538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(drop_index); 1539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds = tab->GetNonMirroredBounds(tabstrip_.get()); 1540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(sky): update these for pinned tabs. 1541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drop_before) 1542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch center_x = bounds.x() - (kTabHOffset / 2); 1543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 1544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch center_x = bounds.x() + (bounds.width() / 2); 1545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* last_tab = GetTabAt(drop_index - 1); 1547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds = last_tab->GetNonMirroredBounds(tabstrip_.get()); 1548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch center_x = bounds.x() + bounds.width() + (kTabHOffset / 2); 1549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch center_x = gtk_util::MirroredXCoordinate(tabstrip_.get(), center_x); 1552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Determine the screen bounds. 1554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point drop_loc(center_x - drop_indicator_width / 2, 1555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch -drop_indicator_height); 1556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_util::ConvertWidgetPointToScreen(tabstrip_.get(), &drop_loc); 1557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect drop_bounds(drop_loc.x(), drop_loc.y(), drop_indicator_width, 1558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_height); 1559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(jhawkins): We always display the arrow underneath the tab because we 1561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // don't have custom frame support yet. 1562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *is_beneath = true; 1563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (*is_beneath) 1564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_bounds.Offset(0, drop_bounds.height() + bounds().height()); 1565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return drop_bounds; 1567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::UpdateDropIndex(GdkDragContext* context, gint x, gint y) { 1570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the UI layout is right-to-left, we need to mirror the mouse 1571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // coordinates since we calculate the drop index based on the 1572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // original (and therefore non-mirrored) positions of the tabs. 1573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch x = gtk_util::MirroredXCoordinate(tabstrip_.get(), x); 1574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't allow replacing the urls of mini-tabs. 1575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = GetMiniTabCount(); i < GetTabCount(); ++i) { 1576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(i); 1577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds = tab->GetNonMirroredBounds(tabstrip_.get()); 1578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int tab_max_x = bounds.x() + bounds.width(); 1579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int hot_width = bounds.width() / 3; 1580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (x < tab_max_x) { 1581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (x < bounds.x() + hot_width) 1582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDropIndex(i, true); 1583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (x >= tab_max_x - hot_width) 1584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDropIndex(i + 1, true); 1585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 1586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDropIndex(i, false); 1587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The drop isn't over a tab, add it to the end. 1592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetDropIndex(GetTabCount(), true); 1593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::SetDropIndex(int index, bool drop_before) { 1596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool is_beneath; 1597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect drop_bounds = GetDropBounds(index, drop_before, &is_beneath); 1598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_info_.get()) { 1600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_.reset(new DropInfo(index, drop_before, !is_beneath)); 1601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GTK_IS_WIDGET(drop_info_->container)) { 1603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->CreateContainer(); 1604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (drop_info_->drop_index == index && 1605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->drop_before == drop_before) { 1606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->drop_index = index; 1610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->drop_before = drop_before; 1611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (is_beneath == drop_info_->point_down) { 1612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->point_down = !is_beneath; 1613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->drop_arrow= GetDropArrowImage(drop_info_->point_down); 1614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_move(GTK_WINDOW(drop_info_->container), 1618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_bounds.x(), drop_bounds.y()); 1619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_resize(GTK_WINDOW(drop_info_->container), 1620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_bounds.width(), drop_bounds.height()); 1621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TabStripGtk::CompleteDrop(guchar* data, bool is_plain_text) { 1624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_info_.get()) 1625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int drop_index = drop_info_->drop_index; 1628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const bool drop_before = drop_info_->drop_before; 1629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Destroy the drop indicator. 1631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_.reset(); 1632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 163321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen GURL url; 163421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (is_plain_text) { 163521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen AutocompleteMatch match; 163621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen model_->profile()->GetAutocompleteClassifier()->Classify( 163772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen UTF8ToUTF16(reinterpret_cast<char*>(data)), string16(), false, 163821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen &match, NULL); 163921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url = match.destination_url; 164021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } else { 164121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::string url_string(reinterpret_cast<char*>(data)); 164221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url = GURL(url_string.substr(0, url_string.find_first_of('\n'))); 164321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 1644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!url.is_valid()) 1645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser::NavigateParams params(window()->browser(), url, 16484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch PageTransition::LINK); 16494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch params.tabstrip_index = drop_index; 16504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drop_before) { 16524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch params.disposition = NEW_FOREGROUND_TAB; 1653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 16544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch params.disposition = CURRENT_TAB; 16554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch params.source_contents = model_->GetTabContentsAt(drop_index); 1656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser::Navigate(¶ms); 16594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 1661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 1664c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGdkPixbuf* TabStripGtk::GetDropArrowImage(bool is_down) { 1665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return ResourceBundle::GetSharedInstance().GetPixbufNamed( 1666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch is_down ? IDR_TAB_DROP_DOWN : IDR_TAB_DROP_UP); 1667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabStripGtk::DropInfo ------------------------------------------------------- 1670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1671c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabStripGtk::DropInfo::DropInfo(int drop_index, bool drop_before, 1672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool point_down) 1673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : drop_index(drop_index), 1674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_before(drop_before), 1675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch point_down(point_down) { 1676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateContainer(); 1677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_arrow = GetDropArrowImage(point_down); 1678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1680c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabStripGtk::DropInfo::~DropInfo() { 1681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DestroyContainer(); 1682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabStripGtk::DropInfo::OnExposeEvent(GtkWidget* widget, 1685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkEventExpose* event) { 1686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (gtk_util::IsScreenComposited()) { 1687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetContainerTransparency(); 1688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetContainerShapeMask(); 1690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_pixbuf_render_to_drawable(drop_arrow, 1693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container->window, 1694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, 0, 0, 1695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, 0, 1696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_width, 1697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_height, 1698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GDK_RGB_DITHER_NONE, 0, 0); 1699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FALSE; 1701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sets the color map of the container window to allow the window to be 1704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// transparent. 1705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DropInfo::SetContainerColorMap() { 1706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkScreen* screen = gtk_widget_get_screen(container); 1707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkColormap* colormap = gdk_screen_get_rgba_colormap(screen); 1708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If rgba is not available, use rgb instead. 1710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!colormap) 1711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch colormap = gdk_screen_get_rgb_colormap(screen); 1712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_colormap(container, colormap); 1714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sets full transparency for the container window. This is used if 1717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// compositing is available for the screen. 1718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DropInfo::SetContainerTransparency() { 1719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_t* cairo_context = gdk_cairo_create(container->window); 1720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!cairo_context) 1721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make the background of the dragged tab window fully transparent. All of 1724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the content of the window (child widgets) will be completely opaque. 1725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_scale(cairo_context, static_cast<double>(drop_indicator_width), 1727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<double>(drop_indicator_height)); 1728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f); 1729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); 1730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_paint(cairo_context); 1731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_destroy(cairo_context); 1732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Sets the shape mask for the container window to emulate a transparent 1735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// container window. This is used if compositing is not available for the 1736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// screen. 1737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DropInfo::SetContainerShapeMask() { 1738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a 1bpp bitmap the size of |container|. 1739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkPixmap* pixmap = gdk_pixmap_new(NULL, 1740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_width, 1741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_height, 1); 1742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(pixmap)); 1743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the transparency. 1745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_source_rgba(cairo_context, 1, 1, 1, 0); 1746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Blit the rendered bitmap into a pixmap. Any pixel set in the pixmap will 1748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be opaque in the container window. 1749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); 1750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_cairo_set_source_pixbuf(cairo_context, drop_arrow, 0, 0); 1751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_paint(cairo_context); 1752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_destroy(cairo_context); 1753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the shape mask. 1755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_window_shape_combine_mask(container->window, pixmap, 0, 0); 1756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_object_unref(pixmap); 1757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DropInfo::CreateContainer() { 1760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container = gtk_window_new(GTK_WINDOW_POPUP); 1761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetContainerColorMap(); 1762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_app_paintable(container, TRUE); 1763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(container, "expose-event", 1764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnExposeEventThunk), this); 1765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_add_events(container, GDK_STRUCTURE_MASK); 1766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_move(GTK_WINDOW(container), 0, 0); 1767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_resize(GTK_WINDOW(container), 1768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_indicator_width, drop_indicator_height); 1769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_show_all(container); 1770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::DropInfo::DestroyContainer() { 1773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GTK_IS_WIDGET(container)) 1774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_destroy(container); 1775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StopAnimation() { 1778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (active_animation_.get()) 1779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Stop(); 1780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called from: 1783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// - animation tick 1784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::AnimationLayout(double unselected_width) { 1785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_height = TabGtk::GetStandardSize().height(); 1786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double tab_x = tab_start_x(); 1787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < GetTabCount(); ++i) { 1788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabAnimation* animation = active_animation_.get(); 1789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (animation) 1790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_x += animation->GetGapWidth(i); 1791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double tab_width = TabAnimation::GetCurrentTabWidth(this, animation, i); 1792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double end_of_tab = tab_x + tab_width; 1793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int rounded_tab_x = Round(tab_x); 1794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(i); 1795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, 1796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_height); 1797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetTabBounds(tab, bounds); 1798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_x = end_of_tab + GetTabHOffset(i + 1); 1799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LayoutNewTabButton(tab_x, unselected_width); 1801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartInsertTabAnimation(int index) { 1804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The TabStrip can now use its entire width to lay out Tabs. 1805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch available_width_for_tabs_ = -1; 1806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 1807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset(new InsertTabAnimation(this, index)); 1808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Start(); 1809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartRemoveTabAnimation(int index, TabContents* contents) { 1812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (active_animation_.get()) { 1813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Some animations (e.g. MoveTabAnimation) cause there to be a Layout when 1814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // they're completed (which includes canceled). Since |tab_data_| is now 1815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // inconsistent with TabStripModel, doing this Layout will crash now, so 1816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we ask the MoveTabAnimation to skip its Layout (the state will be 1817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // corrected by the RemoveTabAnimation we're about to initiate). 1818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->set_layout_on_completion(false); 1819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Stop(); 1820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset(new RemoveTabAnimation(this, index, contents)); 1823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Start(); 1824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartMoveTabAnimation(int from_index, int to_index) { 1827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 1828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset(new MoveTabAnimation(this, from_index, to_index)); 1829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Start(); 1830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartResizeLayoutAnimation() { 1833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 1834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset(new ResizeLayoutAnimation(this)); 1835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Start(); 1836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartMiniTabAnimation(int index) { 1839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 1840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset(new MiniTabAnimation(this, index)); 1841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Start(); 1842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::StartMiniMoveTabAnimation(int from_index, 1845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int to_index, 1846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& start_bounds) { 1847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StopAnimation(); 1848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset( 1849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new MiniMoveAnimation(this, from_index, to_index, start_bounds)); 1850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_->Start(); 1851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::FinishAnimation(TabStripGtk::TabAnimation* animation, 1854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool layout) { 1855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_animation_.reset(NULL); 1856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Reset the animation state of each tab. 1858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0, count = GetTabCount(); i < count; ++i) 1859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetTabAt(i)->set_animating_mini_change(false); 1860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (layout) 1862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 1863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabStripGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event) { 1866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (gdk_region_empty(event->region)) 1867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 1868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we're only repainting favicons, optimize the paint path and only draw 1870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the favicons. 1871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkRectangle* rects; 1872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gint num_rects; 1873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_region_get_rectangles(event->region, &rects, &num_rects); 1874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch qsort(rects, num_rects, sizeof(GdkRectangle), CompareGdkRectangles); 1875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<int> tabs_to_repaint; 1876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!IsDragSessionActive() && 1877ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CanPaintOnlyFavicons(rects, num_rects, &tabs_to_repaint)) { 1878ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PaintOnlyFavicons(event, tabs_to_repaint); 1879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_free(rects); 1880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 1881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_free(rects); 1883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(jhawkins): Ideally we'd like to only draw what's needed in the damage 1885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rect, but the tab widgets overlap each other, and painting on one widget 1886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // will cause an expose-event to be sent to the widgets underneath. The 1887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // underlying widget does not need to be redrawn as we control the order of 1888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // expose-events. Currently we hack it to redraw the entire tabstrip. We 1889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // could change the damage rect to just contain the tabs + the new tab button. 1890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch event->area.x = 0; 1891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch event->area.y = 0; 1892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch event->area.width = bounds_.width(); 1893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch event->area.height = bounds_.height(); 1894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_region_union_with_rect(event->region, &event->area); 1895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Paint the New Tab button. 1897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_propagate_expose(GTK_CONTAINER(tabstrip_.get()), 1898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch newtab_button_->widget(), event); 1899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Paint the tabs in reverse order, so they stack to the left. 1901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* selected_tab = NULL; 1902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_count = GetTabCount(); 1903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = tab_count - 1; i >= 0; --i) { 1904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(i); 1905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We must ask the _Tab's_ model, not ourselves, because in some situations 1906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the model will be different to this object, e.g. when a Tab is being 1907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // removed after its TabContents has been destroyed. 1908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!tab->IsSelected()) { 1909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_propagate_expose(GTK_CONTAINER(tabstrip_.get()), 1910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->widget(), event); 1911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_tab = tab; 1913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Paint the selected tab last, so it overlaps all the others. 1917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (selected_tab) { 1918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_propagate_expose(GTK_CONTAINER(tabstrip_.get()), 1919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_tab->widget(), event); 1920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 1923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { 1926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds = gfx::Rect(allocation->x, allocation->y, 1927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch allocation->width, allocation->height); 1928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Nothing to do if the bounds are the same. If we don't catch this, we'll 1930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // get an infinite loop of size-allocate signals. 1931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (bounds_ == bounds) 1932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetBounds(bounds); 1935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No tabs, nothing to layout. This happens when a browser window is created 1937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and shown before tabs are added (as in a popup window). 1938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (GetTabCount() == 0) 1939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // When there is only one tab, Layout() so we don't animate it. With more 19423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // tabs, do ResizeLayoutTabs(). In RTL(), we will also need to manually 19433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Layout() when ResizeLayoutTabs() is a no-op. 19443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if ((GetTabCount() == 1) || (!ResizeLayoutTabs() && base::i18n::IsRTL())) 1945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Layout(); 1946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabStripGtk::OnDragMotion(GtkWidget* widget, GdkDragContext* context, 1949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gint x, gint y, guint time) { 1950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateDropIndex(context, x, y); 1951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 1952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabStripGtk::OnDragDrop(GtkWidget* widget, GdkDragContext* context, 1955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gint x, gint y, guint time) { 1956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_info_.get()) 1957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FALSE; 1958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkAtom target = gtk_drag_dest_find_target(widget, context, NULL); 1960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (target != GDK_NONE) 1961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_drag_finish(context, FALSE, FALSE, time); 1962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 1963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_drag_get_data(widget, context, target, time); 1964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 1966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabStripGtk::OnDragLeave(GtkWidget* widget, GdkDragContext* context, 1969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch guint time) { 1970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Destroy the drop indicator. 1971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_info_->DestroyContainer(); 1972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FALSE; 1973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabStripGtk::OnDragDataReceived(GtkWidget* widget, 1976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkDragContext* context, 1977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gint x, gint y, 1978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkSelectionData* data, 1979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch guint info, guint time) { 1980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool success = false; 1981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 198272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (info == ui::TEXT_URI_LIST || 198372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen info == ui::NETSCAPE_URL || 198472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen info == ui::TEXT_PLAIN) { 198572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen success = CompleteDrop(data->data, info == ui::TEXT_PLAIN); 1986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_drag_finish(context, success, success, time); 1989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 1990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::OnNewTabClicked(GtkWidget* widget) { 1993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkEvent* event = gtk_get_current_event(); 1994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(event->type, GDK_BUTTON_RELEASE); 1995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int mouse_button = event->button.button; 1996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_event_free(event); 1997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (mouse_button) { 1999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 1: 2000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch model_->delegate()->AddBlankTab(true); 2001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 2002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 2: { 2003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // On middle-click, try to parse the PRIMARY selection as a URL and load 2004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it instead of creating a blank page. 2005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL url; 2006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!gtk_util::URLFromPrimarySelection(model_->profile(), &url)) 2007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 2008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Browser* browser = window_->browser(); 20104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(browser); 20114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser->AddSelectedTabWithURL(url, PageTransition::TYPED); 2012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 2013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 2015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Got click on new tab button with unhandled mouse " 2016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "button " << mouse_button; 2017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 2019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabStripGtk::SetTabBounds(TabGtk* tab, const gfx::Rect& bounds) { 2021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bds = bounds; 2022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bds.set_x(gtk_util::MirroredLeftPointForRect(tabstrip_.get(), bounds)); 2023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab->SetBounds(bds); 2024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_fixed_move(GTK_FIXED(tabstrip_.get()), tab->widget(), 2025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bds.x(), bds.y()); 2026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 2027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2028ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool TabStripGtk::CanPaintOnlyFavicons(const GdkRectangle* rects, 2029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int num_rects, std::vector<int>* tabs_to_paint) { 2030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |rects| are sorted so we just need to scan from left to right and compare 2031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it to the tab favicon positions from left to right. 2032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int t = 0; 2033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int r = 0; r < num_rects; ++r) { 2034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (t < GetTabCount()) { 2035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabGtk* tab = GetTabAt(t); 2036ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (GdkRectMatchesTabFaviconBounds(rects[r], tab) && 2037513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch tab->ShouldShowIcon()) { 2038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tabs_to_paint->push_back(t); 2039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++t; 2040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 2041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++t; 2043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return static_cast<int>(tabs_to_paint->size()) == num_rects; 2046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 2047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2048ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabStripGtk::PaintOnlyFavicons(GdkEventExpose* event, 2049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::vector<int>& tabs_to_paint) { 2050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < tabs_to_paint.size(); ++i) 2051ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetTabAt(tabs_to_paint[i])->PaintFaviconArea(event); 2052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 2053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2054c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawButton* TabStripGtk::MakeNewTabButton() { 2055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON, 2056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0); 2057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Let the middle mouse button initiate clicks as well. 2059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_util::SetButtonTriggersNavigation(button->widget()); 2060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(button->widget(), "clicked", 2061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnNewTabClickedThunk), this); 2062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS); 2063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_fixed_put(GTK_FIXED(tabstrip_.get()), button->widget(), 0, 0); 2064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return button; 2066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 2067