This source file includes following definitions.
- GetEffectiveBounds
 
- initial_move_
 
- CaptureDragInfo
 
- EndDrag
 
- GetDraggedTabForContents
 
- IsDraggingTab
 
- IsDraggingWebContents
 
- IsTabDetached
 
- InitDraggedTabData
 
- OpenURLFromTab
 
- NavigationStateChanged
 
- AddNewContents
 
- LoadingStateChanged
 
- GetJavaScriptDialogManager
 
- Observe
 
- RequestMediaAccessPermission
 
- GetWindowCreatePoint
 
- ContinueDragging
 
- RestoreSelection
 
- MoveAttached
 
- MoveDetached
 
- GetTabStripForPoint
 
- GetTabStripIfItContains
 
- Attach
 
- Detach
 
- ConvertScreenPointToTabStripPoint
 
- GetDraggedViewTabStripBounds
 
- GetInsertionIndexForDraggedBounds
 
- GetDraggedViewPoint
 
- NormalizeIndexToAttachedTabStrip
 
- GetTabMatchingDraggedContents
 
- GetTabsMatchingDraggedContents
 
- SetDraggedTabsVisible
 
- EndDragImpl
 
- RevertDrag
 
- CompleteDrag
 
- ResetDelegates
 
- EnsureDraggedView
 
- GetAnimateBounds
 
- HideWindow
 
- ShowWindow
 
- CleanUpHiddenFrame
 
- CleanUpDraggedTabs
 
- OnAnimateToBoundsComplete
 
- BringWindowUnderMouseToFront
 
- AreTabsConsecutive
 
- GetLocalProcessWindow
 
#include "chrome/browser/ui/gtk/tabs/dragged_tab_controller_gtk.h"
#include <algorithm>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/i18n/rtl.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/tabs/dragged_view_gtk.h"
#include "chrome/browser/ui/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/ui/gtk/tabs/window_finder.h"
#include "chrome/browser/ui/media_utils.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/base/gtk/gtk_screen_util.h"
#include "ui/gfx/screen.h"
using content::OpenURLParams;
using content::WebContents;
namespace {
const int kBringToFrontDelay = 750;
const int kHorizontalMoveThreshold = 16;  
const int kVerticalDetachMagnetism = 15;  
gfx::Rect GetEffectiveBounds(const gfx::Rect& bounds) {
  gfx::Rect effective_bounds(bounds);
  effective_bounds.set_width(effective_bounds.width() - 2 * 16);
  effective_bounds.set_x(effective_bounds.x() + 16);
  return effective_bounds;
}
}  
DraggedTabControllerGtk::DraggedTabControllerGtk(
    TabStripGtk* source_tabstrip,
    TabGtk* source_tab,
    const std::vector<TabGtk*>& tabs)
    : source_tabstrip_(source_tabstrip),
      attached_tabstrip_(source_tabstrip),
      in_destructor_(false),
      last_move_screen_x_(0),
      initial_move_(true) {
  DCHECK(!tabs.empty());
  DCHECK(std::find(tabs.begin(), tabs.end(), source_tab) != tabs.end());
  std::vector<DraggedTabData> drag_data;
  for (size_t i = 0; i < tabs.size(); i++)
    drag_data.push_back(InitDraggedTabData(tabs[i]));
  int source_tab_index =
      std::find(tabs.begin(), tabs.end(), source_tab) - tabs.begin();
  drag_data_.reset(new DragData(drag_data, source_tab_index));
}
DraggedTabControllerGtk::~DraggedTabControllerGtk() {
  in_destructor_ = true;
  
  
  
  
  CleanUpDraggedTabs();
  dragged_view_.reset();
  drag_data_.reset();
}
void DraggedTabControllerGtk::CaptureDragInfo(const gfx::Point& mouse_offset) {
  start_screen_point_ = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
  mouse_offset_ = mouse_offset;
}
void DraggedTabControllerGtk::Drag() {
  if (!drag_data_->GetSourceTabData()->tab_ ||
      !drag_data_->GetSourceWebContents()) {
    return;
  }
  bring_to_front_timer_.Stop();
  EnsureDraggedView();
  
  
  if (drag_data_->GetSourceTabData()->tab_->IsVisible()) {
    Attach(source_tabstrip_, gfx::Point());
  }
  if (!drag_data_->GetSourceTabData()->tab_->IsVisible()) {
    
    ContinueDragging();
  }
}
bool DraggedTabControllerGtk::EndDrag(bool canceled) {
  return EndDragImpl(canceled ? CANCELED : NORMAL);
}
TabGtk* DraggedTabControllerGtk::GetDraggedTabForContents(
    WebContents* contents) {
  if (attached_tabstrip_ == source_tabstrip_) {
    for (size_t i = 0; i < drag_data_->size(); i++) {
      if (contents == drag_data_->get(i)->contents_)
        return drag_data_->get(i)->tab_;
    }
  }
  return NULL;
}
bool DraggedTabControllerGtk::IsDraggingTab(const TabGtk* tab) {
  for (size_t i = 0; i < drag_data_->size(); i++) {
    if (tab == drag_data_->get(i)->tab_)
      return true;
  }
  return false;
}
bool DraggedTabControllerGtk::IsDraggingWebContents(
    const WebContents* web_contents) {
  for (size_t i = 0; i < drag_data_->size(); i++) {
    if (web_contents == drag_data_->get(i)->contents_)
      return true;
  }
  return false;
}
bool DraggedTabControllerGtk::IsTabDetached(const TabGtk* tab) {
  return IsDraggingTab(tab) && attached_tabstrip_ == NULL;
}
DraggedTabData DraggedTabControllerGtk::InitDraggedTabData(TabGtk* tab) {
  int source_model_index = source_tabstrip_->GetIndexOfTab(tab);
  WebContents* contents =
      source_tabstrip_->model()->GetWebContentsAt(source_model_index);
  bool pinned = source_tabstrip_->IsTabPinned(tab);
  bool mini = source_tabstrip_->model()->IsMiniTab(source_model_index);
  
  
  
  
  content::WebContentsDelegate* original_delegate = contents->GetDelegate();
  contents->SetDelegate(this);
  DraggedTabData dragged_tab_data(tab, contents, original_delegate,
                                  source_model_index, pinned, mini);
  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
                 content::Source<WebContents>(contents));
  return dragged_tab_data;
}
WebContents* DraggedTabControllerGtk::OpenURLFromTab(
    WebContents* source,
    const OpenURLParams& params) {
  if (drag_data_->GetSourceTabData()->original_delegate_) {
    OpenURLParams forward_params = params;
    if (params.disposition == CURRENT_TAB)
      forward_params.disposition = NEW_WINDOW;
    return drag_data_->GetSourceTabData()->original_delegate_->
        OpenURLFromTab(source, forward_params);
  }
  return NULL;
}
void DraggedTabControllerGtk::NavigationStateChanged(const WebContents* source,
                                                     unsigned changed_flags) {
  if (dragged_view_.get())
    dragged_view_->Update();
}
void DraggedTabControllerGtk::AddNewContents(WebContents* source,
                                             WebContents* new_contents,
                                             WindowOpenDisposition disposition,
                                             const gfx::Rect& initial_pos,
                                             bool user_gesture,
                                             bool* was_blocked) {
  DCHECK(disposition != CURRENT_TAB);
  
  
  if (drag_data_->GetSourceTabData()->original_delegate_) {
    drag_data_->GetSourceTabData()->original_delegate_->AddNewContents(
        source, new_contents, disposition, initial_pos, user_gesture,
        was_blocked);
  }
}
void DraggedTabControllerGtk::LoadingStateChanged(WebContents* source) {
  
  
  if (dragged_view_.get())
    dragged_view_->Update();
}
content::JavaScriptDialogManager*
DraggedTabControllerGtk::GetJavaScriptDialogManager() {
  return GetJavaScriptDialogManagerInstance();
}
void DraggedTabControllerGtk::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type);
  WebContents* destroyed_web_contents =
      content::Source<WebContents>(source).ptr();
  for (size_t i = 0; i < drag_data_->size(); ++i) {
    if (drag_data_->get(i)->contents_ == destroyed_web_contents) {
      
      if (destroyed_web_contents->GetDelegate() == this)
        destroyed_web_contents->SetDelegate(NULL);
      drag_data_->get(i)->contents_ = NULL;
      drag_data_->get(i)->original_delegate_ = NULL;
      EndDragImpl(TAB_DESTROYED);
      return;
    }
  }
  
  NOTREACHED();
}
void DraggedTabControllerGtk::RequestMediaAccessPermission(
    content::WebContents* web_contents,
    const content::MediaStreamRequest& request,
    const content::MediaResponseCallback& callback) {
  ::RequestMediaAccessPermission(
      web_contents,
      Profile::FromBrowserContext(web_contents->GetBrowserContext()),
      request,
      callback);
}
gfx::Point DraggedTabControllerGtk::GetWindowCreatePoint() const {
  gfx::Point creation_point =
      gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
  gfx::Point distance_from_origin =
      dragged_view_->GetDistanceFromTabStripOriginToMousePointer();
  
  
  creation_point.Offset(-distance_from_origin.x(), -distance_from_origin.y());
  return creation_point;
}
void DraggedTabControllerGtk::ContinueDragging() {
  
  
  
  gfx::Point screen_point =
      gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
  
  
  
  TabStripGtk* target_tabstrip = GetTabStripForPoint(screen_point);
  if (target_tabstrip != attached_tabstrip_) {
    
    
    if (attached_tabstrip_)
      Detach();
    if (target_tabstrip)
      Attach(target_tabstrip, screen_point);
  }
  if (!target_tabstrip) {
    bring_to_front_timer_.Start(FROM_HERE,
        base::TimeDelta::FromMilliseconds(kBringToFrontDelay), this,
        &DraggedTabControllerGtk::BringWindowUnderMouseToFront);
  }
  if (attached_tabstrip_)
    MoveAttached(screen_point);
  else
    MoveDetached(screen_point);
}
void DraggedTabControllerGtk::RestoreSelection(TabStripModel* model) {
  for (size_t i = 0; i < drag_data_->size(); ++i) {
    WebContents* contents = drag_data_->get(i)->contents_;
    
    
    if (contents) {
      int index = model->GetIndexOfWebContents(contents);
      CHECK(index != TabStripModel::kNoTab);
      model->AddTabAtToSelection(index);
    }
  }
}
void DraggedTabControllerGtk::MoveAttached(const gfx::Point& screen_point) {
  DCHECK(attached_tabstrip_);
  gfx::Point dragged_view_point = GetDraggedViewPoint(screen_point);
  TabStripModel* attached_model = attached_tabstrip_->model();
  std::vector<TabGtk*> tabs(drag_data_->GetDraggedTabs());
  
  
  
  double unselected, selected;
  attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected);
  double ratio = unselected / TabGtk::GetStandardSize().width();
  int threshold = static_cast<int>(ratio * kHorizontalMoveThreshold);
  
  
  
  
  if (abs(screen_point.x() - last_move_screen_x_) > threshold ||
      (initial_move_ && !AreTabsConsecutive())) {
    if (initial_move_ && !AreTabsConsecutive()) {
      
      attached_tabstrip_->model()->MoveSelectedTabsTo(
          drag_data_->GetSourceTabData()->source_model_index_ -
              drag_data_->source_tab_index());
    }
    gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point);
    int to_index = GetInsertionIndexForDraggedBounds(
        GetEffectiveBounds(bounds));
    to_index = NormalizeIndexToAttachedTabStrip(to_index);
    last_move_screen_x_ = screen_point.x();
    attached_model->MoveSelectedTabsTo(to_index);
  }
  dragged_view_->MoveAttachedTo(dragged_view_point);
  initial_move_ = false;
}
void DraggedTabControllerGtk::MoveDetached(const gfx::Point& screen_point) {
  DCHECK(!attached_tabstrip_);
  
  
  dragged_view_->MoveDetachedTo(screen_point);
}
TabStripGtk* DraggedTabControllerGtk::GetTabStripForPoint(
    const gfx::Point& screen_point) {
  gfx::NativeWindow local_window = GetLocalProcessWindow(screen_point);
  if (!local_window)
    return NULL;
  BrowserWindowGtk* browser =
      BrowserWindowGtk::GetBrowserWindowForNativeWindow(local_window);
  if (!browser)
    return NULL;
  TabStripGtk* other_tabstrip = browser->tabstrip();
  if (!other_tabstrip->IsCompatibleWith(source_tabstrip_))
    return NULL;
  return GetTabStripIfItContains(other_tabstrip, screen_point);
}
TabStripGtk* DraggedTabControllerGtk::GetTabStripIfItContains(
    TabStripGtk* tabstrip, const gfx::Point& screen_point) const {
  
  
  gfx::Rect tabstrip_bounds =
      ui::GetWidgetScreenBounds(tabstrip->tabstrip_.get());
  if (screen_point.x() < tabstrip_bounds.right() &&
      screen_point.x() >= tabstrip_bounds.x()) {
    
    
    int upper_threshold = tabstrip_bounds.bottom() + kVerticalDetachMagnetism;
    int lower_threshold = tabstrip_bounds.y() - kVerticalDetachMagnetism;
    if (screen_point.y() >= lower_threshold &&
        screen_point.y() <= upper_threshold) {
      return tabstrip;
    }
  }
  return NULL;
}
void DraggedTabControllerGtk::Attach(TabStripGtk* attached_tabstrip,
                                     const gfx::Point& screen_point) {
  attached_tabstrip_ = attached_tabstrip;
  attached_tabstrip_->GenerateIdealBounds();
  std::vector<TabGtk*> attached_dragged_tabs =
      GetTabsMatchingDraggedContents(attached_tabstrip_);
  
  
  
  
  
  
  
  int tab_count = attached_tabstrip_->GetTabCount();
  int mini_tab_count = attached_tabstrip_->GetMiniTabCount();
  if (attached_dragged_tabs.size() == 0) {
    tab_count += drag_data_->size();
    mini_tab_count += drag_data_->mini_tab_count();
  }
  double unselected_width = 0, selected_width = 0;
  attached_tabstrip_->GetDesiredTabWidths(tab_count, mini_tab_count,
                                          &unselected_width, &selected_width);
  GtkWidget* parent_window = gtk_widget_get_parent(
      gtk_widget_get_parent(attached_tabstrip_->tabstrip_.get()));
  gfx::Rect window_bounds = ui::GetWidgetScreenBounds(parent_window);
  dragged_view_->Attach(static_cast<int>(floor(selected_width + 0.5)),
                        TabGtk::GetMiniWidth(), window_bounds.width());
  if (attached_dragged_tabs.size() == 0) {
    
    
    
    
    for (size_t i = 0; i < drag_data_->size(); ++i) {
      drag_data_->get(i)->contents_->SetDelegate(NULL);
      drag_data_->get(i)->original_delegate_ = NULL;
    }
    
    
    
    
    attached_tabstrip_->GenerateIdealBounds();
    
    
    last_move_screen_x_ = screen_point.x();
    
    
    
    
    gfx::Rect bounds =
        GetDraggedViewTabStripBounds(GetDraggedViewPoint(screen_point));
    int index = GetInsertionIndexForDraggedBounds(GetEffectiveBounds(bounds));
    for (size_t i = 0; i < drag_data_->size(); ++i) {
      attached_tabstrip_->model()->InsertWebContentsAt(
          index + i, drag_data_->get(i)->contents_,
          drag_data_->GetAddTypesForDraggedTabAt(i));
    }
    RestoreSelection(attached_tabstrip_->model());
    attached_dragged_tabs = GetTabsMatchingDraggedContents(attached_tabstrip_);
  }
  
  DCHECK(attached_dragged_tabs.size() == drag_data_->size());
  SetDraggedTabsVisible(false, false);
  
}
void DraggedTabControllerGtk::Detach() {
  
  TabStripModel* attached_model = attached_tabstrip_->model();
  for (size_t i = 0; i < drag_data_->size(); ++i) {
    int index =
        attached_model->GetIndexOfWebContents(drag_data_->get(i)->contents_);
    if (index >= 0 && index < attached_model->count()) {
      
      
      attached_model->DetachWebContentsAt(index);
    }
  }
  
  if (attached_model->empty())
    HideWindow();
  
  
  
  if (dragged_view_.get()) {
    dragged_view_->Detach();
  }
  
  for (size_t i = 0; i < drag_data_->size(); ++i)
    drag_data_->get(i)->contents_->SetDelegate(this);
  attached_tabstrip_ = NULL;
}
gfx::Point DraggedTabControllerGtk::ConvertScreenPointToTabStripPoint(
    TabStripGtk* tabstrip, const gfx::Point& screen_point) {
  return screen_point - ui::GetWidgetScreenOffset(tabstrip->tabstrip_.get());
}
gfx::Rect DraggedTabControllerGtk::GetDraggedViewTabStripBounds(
    const gfx::Point& screen_point) {
  gfx::Point client_point =
      ConvertScreenPointToTabStripPoint(attached_tabstrip_, screen_point);
  gfx::Size tab_size = dragged_view_->attached_tab_size();
  return gfx::Rect(client_point.x(), client_point.y(),
                   dragged_view_->GetTotalWidthInTabStrip(), tab_size.height());
}
int DraggedTabControllerGtk::GetInsertionIndexForDraggedBounds(
    const gfx::Rect& dragged_bounds) {
  int dragged_bounds_start = gtk_util::MirroredLeftPointForRect(
      attached_tabstrip_->widget(),
      dragged_bounds);
  int dragged_bounds_end = gtk_util::MirroredRightPointForRect(
      attached_tabstrip_->widget(),
      dragged_bounds);
  int right_tab_x = 0;
  int index = -1;
  for (int i = 0; i < attached_tabstrip_->GetTabCount(); i++) {
    
    
    gfx::Rect ideal_bounds = attached_tabstrip_->GetIdealBounds(i);
    gfx::Rect left_half, right_half;
    ideal_bounds.SplitVertically(&left_half, &right_half);
    right_tab_x = right_half.x();
    if (dragged_bounds_start >= right_half.x() &&
        dragged_bounds_start < right_half.right()) {
      index = i + 1;
      break;
    } else if (dragged_bounds_start >= left_half.x() &&
               dragged_bounds_start < left_half.right()) {
      index = i;
      break;
    }
  }
  if (index == -1) {
    if (dragged_bounds_end > right_tab_x)
      index = attached_tabstrip_->GetTabCount();
    else
      index = 0;
  }
  TabGtk* tab = GetTabMatchingDraggedContents(
      attached_tabstrip_, drag_data_->GetSourceWebContents());
  if (tab == NULL) {
    
    
    return index;
  }
  int max_index =
      attached_tabstrip_-> GetTabCount() - static_cast<int>(drag_data_->size());
  return std::max(0, std::min(max_index, index));
}
gfx::Point DraggedTabControllerGtk::GetDraggedViewPoint(
    const gfx::Point& screen_point) {
  int x = screen_point.x() -
      dragged_view_->GetWidthInTabStripUpToMousePointer();
  int y = screen_point.y() - mouse_offset_.y();
  
  if (attached_tabstrip_) {
    gfx::Rect tabstrip_bounds =
        ui::GetWidgetScreenBounds(attached_tabstrip_->tabstrip_.get());
    
    
    
    if (x < tabstrip_bounds.x() && screen_point.x() >= tabstrip_bounds.x())
      x = tabstrip_bounds.x();
    gfx::Size tab_size = dragged_view_->attached_tab_size();
    int vertical_drag_magnetism = tab_size.height() * 2;
    int vertical_detach_point = tabstrip_bounds.y() - vertical_drag_magnetism;
    if (y < tabstrip_bounds.y() && screen_point.y() >= vertical_detach_point)
      y = tabstrip_bounds.y();
    
    
    
    
    
    int max_x =
        tabstrip_bounds.right() - dragged_view_->GetTotalWidthInTabStrip();
    int max_y = tabstrip_bounds.bottom() - tab_size.height();
    if (x > max_x && screen_point.x() <= tabstrip_bounds.right())
      x = max_x;
    if (y > max_y && screen_point.y() <=
        (tabstrip_bounds.bottom() + vertical_drag_magnetism)) {
      y = max_y;
    }
  }
  return gfx::Point(x, y);
}
int DraggedTabControllerGtk::NormalizeIndexToAttachedTabStrip(int index) const {
  if (index >= attached_tabstrip_->model_->count())
    return attached_tabstrip_->model_->count() - 1;
  if (index == TabStripModel::kNoTab)
    return 0;
  return index;
}
TabGtk* DraggedTabControllerGtk::GetTabMatchingDraggedContents(
    TabStripGtk* tabstrip, WebContents* web_contents) {
  int index = tabstrip->model()->GetIndexOfWebContents(web_contents);
  return index == TabStripModel::kNoTab ? NULL : tabstrip->GetTabAt(index);
}
std::vector<TabGtk*> DraggedTabControllerGtk::GetTabsMatchingDraggedContents(
    TabStripGtk* tabstrip) {
  std::vector<TabGtk*> dragged_tabs;
  for (size_t i = 0; i < drag_data_->size(); ++i) {
    if (!drag_data_->get(i)->contents_)
      continue;
    TabGtk* tab = GetTabMatchingDraggedContents(tabstrip,
                                                drag_data_->get(i)->contents_);
    if (tab)
      dragged_tabs.push_back(tab);
  }
  return dragged_tabs;
}
void DraggedTabControllerGtk::SetDraggedTabsVisible(bool visible,
                                                    bool repaint) {
  std::vector<TabGtk*> dragged_tabs(GetTabsMatchingDraggedContents(
      attached_tabstrip_));
  for (size_t i = 0; i < dragged_tabs.size(); ++i) {
    dragged_tabs[i]->SetVisible(visible);
    dragged_tabs[i]->set_dragging(!visible);
    if (repaint)
      dragged_tabs[i]->SchedulePaint();
  }
}
bool DraggedTabControllerGtk::EndDragImpl(EndDragType type) {
  bring_to_front_timer_.Stop();
  
  
  
  
  
  bool destroy_now = true;
  if (type != TAB_DESTROYED) {
    
    
    
    if (dragged_view_.get()) {
      if (type == CANCELED) {
        RevertDrag();
      } else {
        destroy_now = CompleteDrag();
      }
    }
  } else if (drag_data_->size() > 0) {
    RevertDrag();
  }
  ResetDelegates();
  
  if (destroy_now)
    source_tabstrip_->DestroyDragController();
  return destroy_now;
}
void DraggedTabControllerGtk::RevertDrag() {
  
  bool restore_window = attached_tabstrip_ != source_tabstrip_;
  if (attached_tabstrip_) {
    if (attached_tabstrip_ != source_tabstrip_) {
      
      
      for (size_t i = 0; i < drag_data_->size(); ++i) {
        if (!drag_data_->get(i)->contents_)
          continue;
        int index = attached_tabstrip_->model()->GetIndexOfWebContents(
            drag_data_->get(i)->contents_);
        attached_tabstrip_->model()->DetachWebContentsAt(index);
      }
      
      
      attached_tabstrip_ = source_tabstrip_;
      for (size_t i = 0; i < drag_data_->size(); ++i) {
        if (!drag_data_->get(i)->contents_)
          continue;
        attached_tabstrip_->model()->InsertWebContentsAt(
            drag_data_->get(i)->source_model_index_,
            drag_data_->get(i)->contents_,
            drag_data_->GetAddTypesForDraggedTabAt(i));
      }
    } else {
      
      
      for (size_t i = 0; i < drag_data_->size(); ++i) {
        if (!drag_data_->get(i)->contents_)
          continue;
        int index = attached_tabstrip_->model()->GetIndexOfWebContents(
            drag_data_->get(i)->contents_);
        source_tabstrip_->model()->MoveWebContentsAt(
            index, drag_data_->get(i)->source_model_index_, true);
      }
    }
  } else {
    
    
    attached_tabstrip_ = source_tabstrip_;
    
    
    
    for (size_t i = 0; i < drag_data_->size(); ++i) {
      if (!drag_data_->get(i)->contents_)
        continue;
      source_tabstrip_->model()->InsertWebContentsAt(
          drag_data_->get(i)->source_model_index_,
          drag_data_->get(i)->contents_,
          drag_data_->GetAddTypesForDraggedTabAt(i));
    }
  }
  RestoreSelection(source_tabstrip_->model());
  
  
  
  if (restore_window)
    ShowWindow();
  SetDraggedTabsVisible(true, false);
}
bool DraggedTabControllerGtk::CompleteDrag() {
  bool destroy_immediately = true;
  if (attached_tabstrip_) {
    
    
    dragged_view_->AnimateToBounds(GetAnimateBounds(),
        base::Bind(&DraggedTabControllerGtk::OnAnimateToBoundsComplete,
                   base::Unretained(this)));
    destroy_immediately = false;
  } else {
    
    
    BrowserWindowGtk* window = source_tabstrip_->window();
    gfx::Rect window_bounds = window->GetRestoredBounds();
    window_bounds.set_origin(GetWindowCreatePoint());
    std::vector<TabStripModelDelegate::NewStripContents> contentses;
    for (size_t i = 0; i < drag_data_->size(); ++i) {
      TabStripModelDelegate::NewStripContents item;
      item.web_contents = drag_data_->get(i)->contents_;
      item.add_types = drag_data_->GetAddTypesForDraggedTabAt(i);
      contentses.push_back(item);
    };
    Browser* new_browser =
        source_tabstrip_->model()->delegate()->CreateNewStripWithContents(
            contentses, window_bounds, window->IsMaximized());
    RestoreSelection(new_browser->tab_strip_model());
    new_browser->window()->Show();
    CleanUpHiddenFrame();
  }
  return destroy_immediately;
}
void DraggedTabControllerGtk::ResetDelegates() {
  for (size_t i = 0; i < drag_data_->size(); ++i) {
    if (drag_data_->get(i)->contents_ &&
        drag_data_->get(i)->contents_->GetDelegate() == this) {
      drag_data_->get(i)->ResetDelegate();
    }
  }
}
void DraggedTabControllerGtk::EnsureDraggedView() {
  if (!dragged_view_.get()) {
    gfx::Rect rect;
    drag_data_->GetSourceWebContents()->GetView()->GetContainerBounds(&rect);
    dragged_view_.reset(new DraggedViewGtk(drag_data_.get(), mouse_offset_,
                                           rect.size()));
  }
}
gfx::Rect DraggedTabControllerGtk::GetAnimateBounds() {
  
  
  
  
  
  
  
  std::vector<TabGtk*> tabs = GetTabsMatchingDraggedContents(
      attached_tabstrip_);
  TabGtk* tab = !base::i18n::IsRTL() ? tabs.front() : tabs.back();
  gfx::Rect bounds = tab->GetRequisition();
  GtkWidget* widget = tab->widget();
  GtkWidget* parent = gtk_widget_get_parent(widget);
  bounds.Offset(ui::GetWidgetScreenOffset(parent));
  return gfx::Rect(bounds.x(), bounds.y(),
                   dragged_view_->GetTotalWidthInTabStrip(), bounds.height());
}
void DraggedTabControllerGtk::HideWindow() {
  GtkWidget* tabstrip = source_tabstrip_->widget();
  GtkWindow* window = platform_util::GetTopLevel(tabstrip);
  gtk_widget_hide(GTK_WIDGET(window));
}
void DraggedTabControllerGtk::ShowWindow() {
  GtkWidget* tabstrip = source_tabstrip_->widget();
  GtkWindow* window = platform_util::GetTopLevel(tabstrip);
  gtk_window_present(window);
}
void DraggedTabControllerGtk::CleanUpHiddenFrame() {
  
  
  if (source_tabstrip_->model()->empty())
    source_tabstrip_->model()->delegate()->CloseFrameAfterDragSession();
}
void DraggedTabControllerGtk::CleanUpDraggedTabs() {
  
  
  
  if (attached_tabstrip_ != source_tabstrip_) {
    for (size_t i = 0; i < drag_data_->size(); ++i) {
      if (drag_data_->get(i)->contents_) {
        registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
            content::Source<WebContents>(drag_data_->get(i)->contents_));
      }
      source_tabstrip_->DestroyDraggedTab(drag_data_->get(i)->tab_);
      drag_data_->get(i)->tab_ = NULL;
    }
  }
}
void DraggedTabControllerGtk::OnAnimateToBoundsComplete() {
  
  
  if (attached_tabstrip_)
    SetDraggedTabsVisible(true, true);
  CleanUpHiddenFrame();
  if (!in_destructor_)
    source_tabstrip_->DestroyDragController();
}
void DraggedTabControllerGtk::BringWindowUnderMouseToFront() {
  
  gfx::NativeWindow window = GetLocalProcessWindow(
      gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
  if (window)
    gtk_window_present(GTK_WINDOW(window));
}
bool DraggedTabControllerGtk::AreTabsConsecutive() {
  for (size_t i = 1; i < drag_data_->size(); ++i) {
    if (drag_data_->get(i - 1)->source_model_index_ + 1 !=
        drag_data_->get(i)->source_model_index_) {
      return false;
    }
  }
  return true;
}
gfx::NativeWindow DraggedTabControllerGtk::GetLocalProcessWindow(
    const gfx::Point& screen_point) {
  std::set<GtkWidget*> dragged_window;
  dragged_window.insert(dragged_view_->widget());
  return GetLocalProcessWindowAtPoint(
      gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(),
      dragged_window);
}