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