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 |