| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/views/tabs/tab_overview_drag_controller.h" | 5 #include "chrome/browser/views/tabs/tab_overview_drag_controller.h" |
| 6 | 6 |
| 7 #include "chrome/browser/browser.h" | 7 #include "chrome/browser/browser.h" |
| 8 #include "chrome/browser/browser_window.h" | 8 #include "chrome/browser/browser_window.h" |
| 9 #include "chrome/browser/dock_info.h" | 9 #include "chrome/browser/dock_info.h" |
| 10 #include "chrome/browser/gtk/browser_window_gtk.h" |
| 10 #include "chrome/browser/tab_contents/tab_contents.h" | 11 #include "chrome/browser/tab_contents/tab_contents.h" |
| 11 #include "chrome/browser/tabs/tab_strip_model.h" | 12 #include "chrome/browser/tabs/tab_strip_model.h" |
| 12 #include "chrome/browser/tab_contents/tab_contents.h" | 13 #include "chrome/browser/tab_contents/tab_contents.h" |
| 13 #include "chrome/browser/views/tabs/tab_overview_cell.h" | 14 #include "chrome/browser/views/tabs/tab_overview_cell.h" |
| 14 #include "chrome/browser/views/tabs/tab_overview_controller.h" | 15 #include "chrome/browser/views/tabs/tab_overview_controller.h" |
| 15 #include "chrome/browser/views/tabs/tab_overview_grid.h" | 16 #include "chrome/browser/views/tabs/tab_overview_grid.h" |
| 16 #include "chrome/browser/views/tabs/tab_overview_types.h" | 17 #include "chrome/browser/views/tabs/tab_overview_types.h" |
| 17 #include "chrome/common/notification_service.h" | 18 #include "chrome/common/notification_service.h" |
| 18 #include "views/fill_layout.h" | 19 #include "views/fill_layout.h" |
| 19 #include "views/view.h" | 20 #include "views/view.h" |
| 20 #include "views/widget/root_view.h" | 21 #include "views/widget/root_view.h" |
| 21 #include "views/widget/widget_gtk.h" | 22 #include "views/widget/widget_gtk.h" |
| 22 | 23 |
| 23 TabOverviewDragController::TabOverviewDragController( | 24 TabOverviewDragController::TabOverviewDragController( |
| 24 TabOverviewController* controller) | 25 TabOverviewController* controller) |
| 25 : controller_(controller), | 26 : controller_(controller), |
| 26 original_model_(controller->model()), | 27 original_model_(controller->model()), |
| 27 current_index_(-1), | 28 current_index_(-1), |
| 28 original_index_(-1), | 29 original_index_(-1), |
| 29 detached_tab_(NULL), | 30 detached_tab_(NULL), |
| 30 original_delegate_(NULL), | 31 original_delegate_(NULL), |
| 31 x_offset_(0), | 32 x_offset_(0), |
| 32 y_offset_(0), | 33 y_offset_(0), |
| 33 dragging_(false), | 34 dragging_(false), |
| 34 modifying_model_(false), | 35 modifying_model_(false), |
| 35 detached_window_(NULL) { | 36 detached_window_(NULL), |
| 37 hidden_browser_(NULL), |
| 38 mouse_over_mini_window_(false) { |
| 36 } | 39 } |
| 37 | 40 |
| 38 TabOverviewDragController::~TabOverviewDragController() { | 41 TabOverviewDragController::~TabOverviewDragController() { |
| 39 if (dragging_) | 42 if (dragging_) |
| 40 controller_->DragEnded(); | 43 controller_->DragEnded(); |
| 41 if (original_index_ != -1) | 44 if (original_index_ != -1) |
| 42 RevertDrag(); | 45 RevertDrag(false); |
| 43 } | 46 } |
| 44 | 47 |
| 45 bool TabOverviewDragController::Configure(const gfx::Point& location) { | 48 bool TabOverviewDragController::Configure(const gfx::Point& location) { |
| 46 // Find the cell the user clicked on. | 49 // Find the cell the user clicked on. |
| 47 TabOverviewCell* cell = NULL; | 50 TabOverviewCell* cell = NULL; |
| 48 int index = -1; | 51 int index = -1; |
| 49 for (int i = 0; i < grid()->GetChildViewCount(); ++i) { | 52 for (int i = 0; i < grid()->GetChildViewCount(); ++i) { |
| 50 views::View* child = grid()->GetChildViewAt(i); | 53 views::View* child = grid()->GetChildViewAt(i); |
| 51 if (child->bounds().Contains(location)) { | 54 if (child->bounds().Contains(location)) { |
| 52 index = i; | 55 index = i; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 63 if (!cell->IsPointInThumbnail(cell_point)) | 66 if (!cell->IsPointInThumbnail(cell_point)) |
| 64 return false; | 67 return false; |
| 65 | 68 |
| 66 current_index_ = original_index_ = index; | 69 current_index_ = original_index_ = index; |
| 67 origin_ = location; | 70 origin_ = location; |
| 68 x_offset_ = location.x() - cell->bounds().x(); | 71 x_offset_ = location.x() - cell->bounds().x(); |
| 69 y_offset_ = location.y() - cell->bounds().y(); | 72 y_offset_ = location.y() - cell->bounds().y(); |
| 70 | 73 |
| 71 // Ask the controller to select the cell. | 74 // Ask the controller to select the cell. |
| 72 controller_->SelectTab(index); | 75 controller_->SelectTab(index); |
| 76 |
| 77 if (controller_->browser()) { |
| 78 browser_window_size_ = |
| 79 controller_->browser()->window()->GetNormalBounds().size(); |
| 80 } |
| 81 |
| 73 return true; | 82 return true; |
| 74 } | 83 } |
| 75 | 84 |
| 76 void TabOverviewDragController::Drag(const gfx::Point& location) { | 85 void TabOverviewDragController::Drag(const gfx::Point& location) { |
| 77 if (original_index_ == -1) | 86 if (original_index_ == -1) |
| 78 return; | 87 return; |
| 79 | 88 |
| 80 if (!dragging_ && | 89 if (!dragging_ && |
| 81 views::View::ExceededDragThreshold(location.x() - origin_.x(), | 90 views::View::ExceededDragThreshold(location.x() - origin_.x(), |
| 82 location.y() - origin_.y())) { | 91 location.y() - origin_.y())) { |
| 83 // Start dragging. | 92 // Start dragging. |
| 84 dragging_ = true; | 93 dragging_ = true; |
| 85 controller_->DragStarted(); | 94 controller_->DragStarted(); |
| 86 grid()->set_floating_index(current_index_); | 95 grid()->set_floating_index(current_index_); |
| 87 } | 96 } |
| 88 if (dragging_) | 97 if (dragging_) |
| 89 DragCell(location); | 98 DragCell(location); |
| 90 } | 99 } |
| 91 | 100 |
| 92 void TabOverviewDragController::CommitDrag(const gfx::Point& location) { | 101 void TabOverviewDragController::CommitDrag(const gfx::Point& location) { |
| 93 if (original_index_ == -1) | 102 if (original_index_ == -1) |
| 94 return; | 103 return; |
| 95 | 104 |
| 96 Drag(location); | 105 Drag(location); |
| 97 if (detached_tab_) { | 106 if (detached_tab_) { |
| 98 DropTab(location); | 107 if (mouse_over_mini_window_) { |
| 108 // Dragged over a mini window, add as the last tab to the browser. |
| 109 Attach(model()->count()); |
| 110 } else { |
| 111 DropTab(location); |
| 112 } |
| 99 } else if (!dragging_ ) { | 113 } else if (!dragging_ ) { |
| 100 // We haven't started dragging. Tell the controller to focus the browser. | 114 // We haven't started dragging. Tell the controller to focus the browser. |
| 101 controller_->FocusBrowser(); | 115 controller_->FocusBrowser(); |
| 102 } else { | 116 } else { |
| 103 // The tab is already in position, nothing to do but animate the change. | 117 // The tab is already in position, nothing to do but animate the change. |
| 104 grid()->set_floating_index(-1); | 118 grid()->set_floating_index(-1); |
| 105 grid()->AnimateToTargetBounds(); | 119 grid()->AnimateToTargetBounds(); |
| 106 } | 120 } |
| 107 | 121 |
| 108 // Set the index to -1 so we know not to do any cleanup. | 122 // Set the index to -1 so we know not to do any cleanup. |
| 109 original_index_ = -1; | 123 original_index_ = -1; |
| 110 } | 124 } |
| 111 | 125 |
| 112 void TabOverviewDragController::RevertDrag() { | 126 void TabOverviewDragController::RevertDrag(bool tab_destroyed) { |
| 113 if (original_index_ == -1) | 127 if (original_index_ == -1) |
| 114 return; | 128 return; |
| 115 | 129 |
| 116 modifying_model_ = true; | 130 modifying_model_ = true; |
| 117 if (detached_tab_) { | 131 if (detached_tab_) { |
| 118 // Tab is currently detached, add it back to the original tab strip. | 132 // Tab is currently detached, add it back to the original tab strip. |
| 119 original_model_->InsertTabContentsAt(original_index_, | 133 if (!tab_destroyed) { |
| 120 detached_tab_, true, false); | 134 original_model_->InsertTabContentsAt(original_index_, |
| 135 detached_tab_, true, false); |
| 136 } |
| 121 SetDetachedContents(NULL); | 137 SetDetachedContents(NULL); |
| 122 detached_window_->Close(); | 138 detached_window_->Close(); |
| 123 detached_window_ = NULL; | 139 detached_window_ = NULL; |
| 124 } else if (original_model_ != model()) { | 140 |
| 141 if (hidden_browser_) { |
| 142 gtk_widget_show(GTK_WIDGET(static_cast<BrowserWindowGtk*>( |
| 143 hidden_browser_->window())->GetNativeHandle())); |
| 144 } |
| 145 } else if (original_model_ != model() && !tab_destroyed) { |
| 125 // The tab was added to a different tab strip. Move it back to the | 146 // The tab was added to a different tab strip. Move it back to the |
| 126 // original. | 147 // original. |
| 127 TabContents* contents = model()->DetachTabContentsAt(current_index_); | 148 TabContents* contents = model()->DetachTabContentsAt(current_index_); |
| 128 original_model_->InsertTabContentsAt(original_index_, contents, true, | 149 original_model_->InsertTabContentsAt(original_index_, contents, true, |
| 129 false); | 150 false); |
| 130 } else if (current_index_ != original_index_) { | 151 } else if (current_index_ != original_index_ && !tab_destroyed) { |
| 131 original_model_->MoveTabContentsAt(current_index_, original_index_, true); | 152 original_model_->MoveTabContentsAt(current_index_, original_index_, true); |
| 132 } | 153 } |
| 133 modifying_model_ = false; | 154 modifying_model_ = false; |
| 134 | 155 |
| 135 // Set the index to -1 so we know not to do any cleanup. | 156 // Set the index to -1 so we know not to do any cleanup. |
| 136 original_index_ = -1; | 157 original_index_ = -1; |
| 137 } | 158 } |
| 138 | 159 |
| 139 TabOverviewGrid* TabOverviewDragController::grid() const { | 160 TabOverviewGrid* TabOverviewDragController::grid() const { |
| 140 return controller_->grid(); | 161 return controller_->grid(); |
| 141 } | 162 } |
| 142 | 163 |
| 143 TabStripModel* TabOverviewDragController::model() const { | 164 TabStripModel* TabOverviewDragController::model() const { |
| 144 return controller_->model(); | 165 return controller_->model(); |
| 145 } | 166 } |
| 146 | 167 |
| 147 void TabOverviewDragController::Observe(NotificationType type, | 168 void TabOverviewDragController::Observe(NotificationType type, |
| 148 const NotificationSource& source, | 169 const NotificationSource& source, |
| 149 const NotificationDetails& details) { | 170 const NotificationDetails& details) { |
| 150 DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED); | 171 DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED); |
| 151 DCHECK(Source<TabContents>(source).ptr() == detached_tab_); | 172 DCHECK(Source<TabContents>(source).ptr() == detached_tab_); |
| 152 RevertDrag(); | 173 RevertDrag(true); |
| 153 } | 174 } |
| 154 | 175 |
| 155 void TabOverviewDragController::OpenURLFromTab( | 176 void TabOverviewDragController::OpenURLFromTab( |
| 156 TabContents* source, | 177 TabContents* source, |
| 157 const GURL& url, | 178 const GURL& url, |
| 158 const GURL& referrer, | 179 const GURL& referrer, |
| 159 WindowOpenDisposition disposition, | 180 WindowOpenDisposition disposition, |
| 160 PageTransition::Type transition) { | 181 PageTransition::Type transition) { |
| 161 if (original_delegate_) { | 182 if (original_delegate_) { |
| 162 if (disposition == CURRENT_TAB) | 183 if (disposition == CURRENT_TAB) |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 | 340 |
| 320 grid()->set_floating_index(-1); | 341 grid()->set_floating_index(-1); |
| 321 SetDetachedContents(model()->GetTabContentsAt(current_index_)); | 342 SetDetachedContents(model()->GetTabContentsAt(current_index_)); |
| 322 if (model()->count() == 1) { | 343 if (model()->count() == 1) { |
| 323 // The model is going to be empty. Tell the host to move us offscreen. | 344 // The model is going to be empty. Tell the host to move us offscreen. |
| 324 // NOTE: it would be nice to hide and destroy the window here but this | 345 // NOTE: it would be nice to hide and destroy the window here but this |
| 325 // causes two problems: we'll stop getting events, and we don't want | 346 // causes two problems: we'll stop getting events, and we don't want |
| 326 // to empty out the tabstrip as otherwise they may trigger Chrome to | 347 // to empty out the tabstrip as otherwise they may trigger Chrome to |
| 327 // exit. | 348 // exit. |
| 328 controller_->MoveOffscreen(); | 349 controller_->MoveOffscreen(); |
| 350 hidden_browser_ = controller_->browser(); |
| 351 gtk_widget_hide(GTK_WIDGET(static_cast<BrowserWindowGtk*>( |
| 352 hidden_browser_->window())->GetNativeHandle())); |
| 329 } | 353 } |
| 330 modifying_model_ = true; | 354 modifying_model_ = true; |
| 331 model()->DetachTabContentsAt(current_index_); | 355 model()->DetachTabContentsAt(current_index_); |
| 332 modifying_model_ = false; | 356 modifying_model_ = false; |
| 333 } | 357 } |
| 334 | 358 |
| 335 void TabOverviewDragController::DropTab(const gfx::Point& location) { | 359 void TabOverviewDragController::DropTab(const gfx::Point& location) { |
| 336 TabContents* contents = detached_tab_; | 360 TabContents* contents = detached_tab_; |
| 337 SetDetachedContents(NULL); | 361 SetDetachedContents(NULL); |
| 338 | 362 |
| 339 gfx::Rect browser_rect = controller_->browser()->window()->GetNormalBounds(); | |
| 340 gfx::Point screen_loc(location); | 363 gfx::Point screen_loc(location); |
| 341 grid()->ConvertPointToScreen(grid(), &screen_loc); | 364 grid()->ConvertPointToScreen(grid(), &screen_loc); |
| 342 gfx::Rect window_bounds( | 365 gfx::Rect window_bounds(screen_loc, browser_window_size_); |
| 343 screen_loc, gfx::Size(browser_rect.width(), browser_rect.height())); | 366 Browser* new_browser = |
| 344 Browser* new_browser = model()->delegate()->CreateNewStripWithContents( | 367 original_model_->delegate()->CreateNewStripWithContents( |
| 345 contents, window_bounds, DockInfo()); | 368 contents, window_bounds, DockInfo()); |
| 346 new_browser->window()->Show(); | 369 new_browser->window()->Show(); |
| 347 | 370 |
| 348 detached_window_->Close(); | 371 detached_window_->Close(); |
| 349 detached_window_ = NULL; | 372 detached_window_ = NULL; |
| 350 } | 373 } |
| 351 | 374 |
| 352 void TabOverviewDragController::MoveDetachedWindow( | 375 void TabOverviewDragController::MoveDetachedWindow( |
| 353 const gfx::Point& location) { | 376 const gfx::Point& location) { |
| 354 gfx::Point screen_loc = location; | 377 gfx::Point screen_loc = location; |
| 355 screen_loc.Offset(-x_offset_, -y_offset_); | 378 screen_loc.Offset(-x_offset_, -y_offset_); |
| 356 grid()->ConvertPointToScreen(grid(), &screen_loc); | 379 grid()->ConvertPointToScreen(grid(), &screen_loc); |
| 357 detached_window_->SetBounds( | 380 detached_window_->SetBounds( |
| 358 gfx::Rect(screen_loc, | 381 gfx::Rect(screen_loc, |
| 359 detached_window_->GetRootView()->GetPreferredSize())); | 382 detached_window_->GetRootView()->GetPreferredSize())); |
| 383 |
| 384 // Notify the wm of the move. |
| 385 TabOverviewTypes::Message message; |
| 386 message.set_type(TabOverviewTypes::Message::WM_MOVE_FLOATING_TAB); |
| 387 message.set_param(0, x11_util::GetX11WindowFromGtkWidget( |
| 388 detached_window_->GetNativeView())); |
| 389 message.set_param(1, screen_loc.x() + x_offset_); |
| 390 message.set_param(2, screen_loc.y() + y_offset_); |
| 391 TabOverviewTypes::instance()->SendMessage(message); |
| 360 } | 392 } |
| 361 | 393 |
| 362 views::Widget* TabOverviewDragController::CreateDetachedWindow( | 394 views::Widget* TabOverviewDragController::CreateDetachedWindow( |
| 363 const gfx::Point& location, | 395 const gfx::Point& location, |
| 364 TabContents* tab_contents) { | 396 TabContents* tab_contents) { |
| 365 // TODO: wrap the cell in another view that provides a background. | 397 // TODO: wrap the cell in another view that provides a background. |
| 366 views::WidgetGtk* widget = | 398 views::WidgetGtk* widget = |
| 367 new views::WidgetGtk(views::WidgetGtk::TYPE_POPUP); | 399 new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW); |
| 368 widget->MakeTransparent(); | 400 widget->MakeTransparent(); |
| 369 gfx::Point screen_loc = location; | 401 gfx::Point screen_loc = location; |
| 370 screen_loc.Offset(-x_offset_, -y_offset_); | 402 screen_loc.Offset(-x_offset_, -y_offset_); |
| 371 grid()->ConvertPointToScreen(grid(), &screen_loc); | 403 grid()->ConvertPointToScreen(grid(), &screen_loc); |
| 372 TabOverviewCell* cell = new TabOverviewCell(); | 404 TabOverviewCell* cell = new TabOverviewCell(); |
| 373 cell->set_preferred_size( | 405 cell->set_preferred_size( |
| 374 gfx::Size(grid()->cell_width(), grid()->cell_height())); | 406 gfx::Size(grid()->cell_width(), grid()->cell_height())); |
| 375 controller_->ConfigureCell(cell, tab_contents); | 407 controller_->ConfigureCell(cell, tab_contents); |
| 376 widget->Init(NULL, gfx::Rect(screen_loc, cell->GetPreferredSize()), true); | 408 widget->Init(NULL, gfx::Rect(screen_loc, cell->GetPreferredSize()), true); |
| 377 widget->GetRootView()->SetLayoutManager(new views::FillLayout()); | 409 widget->GetRootView()->SetLayoutManager(new views::FillLayout()); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 408 Source<TabContents>(tab)); | 440 Source<TabContents>(tab)); |
| 409 | 441 |
| 410 // We need to be the delegate so we receive messages about stuff, | 442 // We need to be the delegate so we receive messages about stuff, |
| 411 // otherwise our dragged contents may be replaced and subsequently | 443 // otherwise our dragged contents may be replaced and subsequently |
| 412 // collected/destroyed while the drag is in process, leading to | 444 // collected/destroyed while the drag is in process, leading to |
| 413 // nasty crashes. | 445 // nasty crashes. |
| 414 original_delegate_ = tab->delegate(); | 446 original_delegate_ = tab->delegate(); |
| 415 tab->set_delegate(this); | 447 tab->set_delegate(this); |
| 416 } | 448 } |
| 417 } | 449 } |
| OLD | NEW |