| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/views/tabs/tab_drag_controller.h" | 5 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/auto_reset.h" | 10 #include "base/auto_reset.h" |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 | 174 |
| 175 // static | 175 // static |
| 176 const int TabDragController::kVerticalDetachMagnetism = 15; | 176 const int TabDragController::kVerticalDetachMagnetism = 15; |
| 177 | 177 |
| 178 TabDragController::TabDragController() | 178 TabDragController::TabDragController() |
| 179 : event_source_(EVENT_SOURCE_MOUSE), | 179 : event_source_(EVENT_SOURCE_MOUSE), |
| 180 source_tabstrip_(NULL), | 180 source_tabstrip_(NULL), |
| 181 attached_tabstrip_(NULL), | 181 attached_tabstrip_(NULL), |
| 182 screen_(NULL), | 182 screen_(NULL), |
| 183 host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE), | 183 host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE), |
| 184 use_aura_capture_policy_(false), | 184 can_release_capture_(true), |
| 185 offset_to_width_ratio_(0), | 185 offset_to_width_ratio_(0), |
| 186 old_focused_view_id_( | 186 old_focused_view_id_( |
| 187 views::ViewStorage::GetInstance()->CreateStorageID()), | 187 views::ViewStorage::GetInstance()->CreateStorageID()), |
| 188 last_move_screen_loc_(0), | 188 last_move_screen_loc_(0), |
| 189 started_drag_(false), | 189 started_drag_(false), |
| 190 active_(true), | 190 active_(true), |
| 191 source_tab_index_(std::numeric_limits<size_t>::max()), | 191 source_tab_index_(std::numeric_limits<size_t>::max()), |
| 192 initial_move_(true), | 192 initial_move_(true), |
| 193 detach_behavior_(DETACHABLE), | 193 detach_behavior_(DETACHABLE), |
| 194 move_behavior_(REORDER), | 194 move_behavior_(REORDER), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 EventSource event_source) { | 241 EventSource event_source) { |
| 242 DCHECK(!tabs.empty()); | 242 DCHECK(!tabs.empty()); |
| 243 DCHECK(std::find(tabs.begin(), tabs.end(), source_tab) != tabs.end()); | 243 DCHECK(std::find(tabs.begin(), tabs.end(), source_tab) != tabs.end()); |
| 244 source_tabstrip_ = source_tabstrip; | 244 source_tabstrip_ = source_tabstrip; |
| 245 was_source_maximized_ = source_tabstrip->GetWidget()->IsMaximized(); | 245 was_source_maximized_ = source_tabstrip->GetWidget()->IsMaximized(); |
| 246 was_source_fullscreen_ = source_tabstrip->GetWidget()->IsFullscreen(); | 246 was_source_fullscreen_ = source_tabstrip->GetWidget()->IsFullscreen(); |
| 247 screen_ = gfx::Screen::GetScreenFor( | 247 screen_ = gfx::Screen::GetScreenFor( |
| 248 source_tabstrip->GetWidget()->GetNativeView()); | 248 source_tabstrip->GetWidget()->GetNativeView()); |
| 249 host_desktop_type_ = chrome::GetHostDesktopTypeForNativeView( | 249 host_desktop_type_ = chrome::GetHostDesktopTypeForNativeView( |
| 250 source_tabstrip->GetWidget()->GetNativeView()); | 250 source_tabstrip->GetWidget()->GetNativeView()); |
| 251 // Do not release capture when transferring capture between widgets on: |
| 252 // - Desktop Linux |
| 253 // Mouse capture is not synchronous on desktop Linux. Chrome makes |
| 254 // transferring capture between widgets without releasing capture appear |
| 255 // synchronous on desktop Linux, so use that. |
| 256 // - Ash |
| 257 // Releasing capture on Ash cancels gestures so avoid it. |
| 251 #if defined(OS_LINUX) | 258 #if defined(OS_LINUX) |
| 252 use_aura_capture_policy_ = true; | 259 can_release_capture_ = false; |
| 253 #else | 260 #else |
| 254 use_aura_capture_policy_ = | 261 can_release_capture_ = |
| 255 (host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH); | 262 (host_desktop_type_ != chrome::HOST_DESKTOP_TYPE_ASH); |
| 256 #endif | 263 #endif |
| 257 start_point_in_screen_ = gfx::Point(source_tab_offset, mouse_offset.y()); | 264 start_point_in_screen_ = gfx::Point(source_tab_offset, mouse_offset.y()); |
| 258 views::View::ConvertPointToScreen(source_tab, &start_point_in_screen_); | 265 views::View::ConvertPointToScreen(source_tab, &start_point_in_screen_); |
| 259 event_source_ = event_source; | 266 event_source_ = event_source; |
| 260 mouse_offset_ = mouse_offset; | 267 mouse_offset_ = mouse_offset; |
| 261 move_behavior_ = move_behavior; | 268 move_behavior_ = move_behavior; |
| 262 last_point_in_screen_ = start_point_in_screen_; | 269 last_point_in_screen_ = start_point_in_screen_; |
| 263 last_move_screen_loc_ = start_point_in_screen_.x(); | 270 last_move_screen_loc_ = start_point_in_screen_.x(); |
| 264 initial_tab_positions_ = source_tabstrip->GetTabXCoordinates(); | 271 initial_tab_positions_ = source_tabstrip->GetTabXCoordinates(); |
| 265 | 272 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 "point_in_screen", point_in_screen.ToString()); | 572 "point_in_screen", point_in_screen.ToString()); |
| 566 | 573 |
| 567 if (!target_tabstrip) { | 574 if (!target_tabstrip) { |
| 568 DetachIntoNewBrowserAndRunMoveLoop(point_in_screen); | 575 DetachIntoNewBrowserAndRunMoveLoop(point_in_screen); |
| 569 return DRAG_BROWSER_RESULT_STOP; | 576 return DRAG_BROWSER_RESULT_STOP; |
| 570 } | 577 } |
| 571 if (is_dragging_window_) { | 578 if (is_dragging_window_) { |
| 572 // ReleaseCapture() is going to result in calling back to us (because it | 579 // ReleaseCapture() is going to result in calling back to us (because it |
| 573 // results in a move). That'll cause all sorts of problems. Reset the | 580 // results in a move). That'll cause all sorts of problems. Reset the |
| 574 // observer so we don't get notified and process the event. | 581 // observer so we don't get notified and process the event. |
| 575 if (use_aura_capture_policy_) { | 582 if (host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH) { |
| 576 move_loop_widget_->RemoveObserver(this); | 583 move_loop_widget_->RemoveObserver(this); |
| 577 move_loop_widget_ = NULL; | 584 move_loop_widget_ = NULL; |
| 578 } | 585 } |
| 579 views::Widget* browser_widget = GetAttachedBrowserWidget(); | 586 views::Widget* browser_widget = GetAttachedBrowserWidget(); |
| 580 // Need to release the drag controller before starting the move loop as it's | 587 // Need to release the drag controller before starting the move loop as it's |
| 581 // going to trigger capture lost, which cancels drag. | 588 // going to trigger capture lost, which cancels drag. |
| 582 attached_tabstrip_->ReleaseDragController(); | 589 attached_tabstrip_->ReleaseDragController(); |
| 583 target_tabstrip->OwnDragController(this); | 590 target_tabstrip->OwnDragController(this); |
| 584 // Disable animations so that we don't see a close animation on aero. | 591 // Disable animations so that we don't see a close animation on aero. |
| 585 browser_widget->SetVisibilityChangedAnimationsEnabled(false); | 592 browser_widget->SetVisibilityChangedAnimationsEnabled(false); |
| 586 // For aura we can't release capture, otherwise it'll cancel a gesture. | 593 if (can_release_capture_) |
| 587 // Instead we have to directly change capture. | 594 browser_widget->ReleaseCapture(); |
| 588 if (use_aura_capture_policy_) | 595 else |
| 589 target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_); | 596 target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_); |
| 590 else | |
| 591 browser_widget->ReleaseCapture(); | |
| 592 #if defined(OS_WIN) | 597 #if defined(OS_WIN) |
| 593 // The Gesture recognizer does not work well currently when capture changes | 598 // The Gesture recognizer does not work well currently when capture changes |
| 594 // while a touch gesture is in progress. So we need to manually transfer | 599 // while a touch gesture is in progress. So we need to manually transfer |
| 595 // gesture sequence and the GR's touch events queue to the new window. This | 600 // gesture sequence and the GR's touch events queue to the new window. This |
| 596 // should really be done somewhere in capture change code and or inside the | 601 // should really be done somewhere in capture change code and or inside the |
| 597 // GR. But we currently do not have a consistent way for doing it that would | 602 // GR. But we currently do not have a consistent way for doing it that would |
| 598 // work in all cases. Hence this hack. | 603 // work in all cases. Hence this hack. |
| 599 ui::GestureRecognizer::Get()->TransferEventsTo( | 604 ui::GestureRecognizer::Get()->TransferEventsTo( |
| 600 browser_widget->GetNativeView(), | 605 browser_widget->GetNativeView(), |
| 601 target_tabstrip->GetWidget()->GetNativeView()); | 606 target_tabstrip->GetWidget()->GetNativeView()); |
| 602 #endif | 607 #endif |
| 603 | 608 |
| 604 // The window is going away. Since the drag is still on going we don't want | 609 // The window is going away. Since the drag is still on going we don't want |
| 605 // that to effect the position of any windows. | 610 // that to effect the position of any windows. |
| 606 SetWindowPositionManaged(browser_widget->GetNativeView(), false); | 611 SetWindowPositionManaged(browser_widget->GetNativeView(), false); |
| 607 | 612 |
| 608 #if !defined(OS_LINUX) || defined(OS_CHROMEOS) | 613 #if !defined(OS_LINUX) || defined(OS_CHROMEOS) |
| 609 // EndMoveLoop is going to snap the window back to its original location. | 614 // EndMoveLoop is going to snap the window back to its original location. |
| 610 // Hide it so users don't see this. Hiding a window in Linux aura causes | 615 // Hide it so users don't see this. Hiding a window in Linux aura causes |
| 611 // it to lose capture so skip it. | 616 // it to lose capture so skip it. |
| 612 browser_widget->Hide(); | 617 browser_widget->Hide(); |
| 613 #endif | 618 #endif |
| 614 browser_widget->EndMoveLoop(); | 619 browser_widget->EndMoveLoop(); |
| 615 | 620 |
| 616 // Ideally we would always swap the tabs now, but on non-ash it seems that | 621 // Ideally we would always swap the tabs now, but on non-ash Windows, it |
| 617 // running the move loop implicitly activates the window when done, leading | 622 // seems that running the move loop implicitly activates the window when |
| 618 // to all sorts of flicker. So, on non-ash, instead we process the move | 623 // done, leading to all sorts of flicker. So, on non-ash Windows, instead |
| 619 // after the loop completes. But on chromeos, we can do tab swapping now to | 624 // we process the move after the loop completes. But on chromeos, we can |
| 620 // avoid the tab flashing issue(crbug.com/116329). | 625 // do tab swapping now to avoid the tab flashing issue |
| 621 if (use_aura_capture_policy_) { | 626 // (crbug.com/116329). |
| 627 if (can_release_capture_) { |
| 628 tab_strip_to_attach_to_after_exit_ = target_tabstrip; |
| 629 } else { |
| 622 is_dragging_window_ = false; | 630 is_dragging_window_ = false; |
| 623 Detach(DONT_RELEASE_CAPTURE); | 631 Detach(DONT_RELEASE_CAPTURE); |
| 624 Attach(target_tabstrip, point_in_screen); | 632 Attach(target_tabstrip, point_in_screen); |
| 625 // Move the tabs into position. | 633 // Move the tabs into position. |
| 626 MoveAttached(point_in_screen); | 634 MoveAttached(point_in_screen); |
| 627 attached_tabstrip_->GetWidget()->Activate(); | 635 attached_tabstrip_->GetWidget()->Activate(); |
| 628 } else { | |
| 629 tab_strip_to_attach_to_after_exit_ = target_tabstrip; | |
| 630 } | 636 } |
| 631 | 637 |
| 632 waiting_for_run_loop_to_exit_ = true; | 638 waiting_for_run_loop_to_exit_ = true; |
| 633 end_run_loop_behavior_ = END_RUN_LOOP_CONTINUE_DRAGGING; | 639 end_run_loop_behavior_ = END_RUN_LOOP_CONTINUE_DRAGGING; |
| 634 return DRAG_BROWSER_RESULT_STOP; | 640 return DRAG_BROWSER_RESULT_STOP; |
| 635 } | 641 } |
| 636 Detach(DONT_RELEASE_CAPTURE); | 642 Detach(DONT_RELEASE_CAPTURE); |
| 637 Attach(target_tabstrip, point_in_screen); | 643 Attach(target_tabstrip, point_in_screen); |
| 638 return DRAG_BROWSER_RESULT_CONTINUE; | 644 return DRAG_BROWSER_RESULT_CONTINUE; |
| 639 } | 645 } |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 std::vector<gfx::Rect> drag_bounds = CalculateBoundsForDraggedTabs(); | 1014 std::vector<gfx::Rect> drag_bounds = CalculateBoundsForDraggedTabs(); |
| 1009 OffsetX(GetAttachedDragPoint(point_in_screen).x(), &drag_bounds); | 1015 OffsetX(GetAttachedDragPoint(point_in_screen).x(), &drag_bounds); |
| 1010 | 1016 |
| 1011 gfx::Vector2d drag_offset; | 1017 gfx::Vector2d drag_offset; |
| 1012 Browser* browser = CreateBrowserForDrag( | 1018 Browser* browser = CreateBrowserForDrag( |
| 1013 attached_tabstrip_, point_in_screen, &drag_offset, &drag_bounds); | 1019 attached_tabstrip_, point_in_screen, &drag_offset, &drag_bounds); |
| 1014 #if defined(OS_WIN) | 1020 #if defined(OS_WIN) |
| 1015 gfx::NativeView attached_native_view = | 1021 gfx::NativeView attached_native_view = |
| 1016 attached_tabstrip_->GetWidget()->GetNativeView(); | 1022 attached_tabstrip_->GetWidget()->GetNativeView(); |
| 1017 #endif | 1023 #endif |
| 1018 Detach(use_aura_capture_policy_ ? DONT_RELEASE_CAPTURE : RELEASE_CAPTURE); | 1024 Detach(can_release_capture_ ? RELEASE_CAPTURE : DONT_RELEASE_CAPTURE); |
| 1019 BrowserView* dragged_browser_view = | 1025 BrowserView* dragged_browser_view = |
| 1020 BrowserView::GetBrowserViewForBrowser(browser); | 1026 BrowserView::GetBrowserViewForBrowser(browser); |
| 1021 views::Widget* dragged_widget = dragged_browser_view->GetWidget(); | 1027 views::Widget* dragged_widget = dragged_browser_view->GetWidget(); |
| 1022 #if defined(OS_WIN) | 1028 #if defined(OS_WIN) |
| 1023 // The Gesture recognizer does not work well currently when capture changes | 1029 // The Gesture recognizer does not work well currently when capture changes |
| 1024 // while a touch gesture is in progress. So we need to manually transfer | 1030 // while a touch gesture is in progress. So we need to manually transfer |
| 1025 // gesture sequence and the GR's touch events queue to the new window. This | 1031 // gesture sequence and the GR's touch events queue to the new window. This |
| 1026 // should really be done somewhere in capture change code and or inside the | 1032 // should really be done somewhere in capture change code and or inside the |
| 1027 // GR. But we currently do not have a consistent way for doing it that would | 1033 // GR. But we currently do not have a consistent way for doing it that would |
| 1028 // work in all cases. Hence this hack. | 1034 // work in all cases. Hence this hack. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1053 void TabDragController::RunMoveLoop(const gfx::Vector2d& drag_offset) { | 1059 void TabDragController::RunMoveLoop(const gfx::Vector2d& drag_offset) { |
| 1054 // If the user drags the whole window we'll assume they are going to attach to | 1060 // If the user drags the whole window we'll assume they are going to attach to |
| 1055 // another window and therefore want to reorder. | 1061 // another window and therefore want to reorder. |
| 1056 move_behavior_ = REORDER; | 1062 move_behavior_ = REORDER; |
| 1057 | 1063 |
| 1058 move_loop_widget_ = GetAttachedBrowserWidget(); | 1064 move_loop_widget_ = GetAttachedBrowserWidget(); |
| 1059 DCHECK(move_loop_widget_); | 1065 DCHECK(move_loop_widget_); |
| 1060 move_loop_widget_->AddObserver(this); | 1066 move_loop_widget_->AddObserver(this); |
| 1061 is_dragging_window_ = true; | 1067 is_dragging_window_ = true; |
| 1062 base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr()); | 1068 base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr()); |
| 1063 // Running the move loop releases mouse capture on non-ash, which triggers | 1069 if (can_release_capture_) { |
| 1064 // destroying the drag loop. Release mouse capture ourself before this while | 1070 // Running the move loop releases mouse capture, which triggers destroying |
| 1065 // the DragController isn't owned by the TabStrip. | 1071 // the drag loop. Release mouse capture now while the DragController is not |
| 1066 if (host_desktop_type_ != chrome::HOST_DESKTOP_TYPE_ASH) { | 1072 // owned by the TabStrip. |
| 1067 attached_tabstrip_->ReleaseDragController(); | 1073 attached_tabstrip_->ReleaseDragController(); |
| 1068 attached_tabstrip_->GetWidget()->ReleaseCapture(); | 1074 attached_tabstrip_->GetWidget()->ReleaseCapture(); |
| 1069 attached_tabstrip_->OwnDragController(this); | 1075 attached_tabstrip_->OwnDragController(this); |
| 1070 } | 1076 } |
| 1071 const views::Widget::MoveLoopSource move_loop_source = | 1077 const views::Widget::MoveLoopSource move_loop_source = |
| 1072 event_source_ == EVENT_SOURCE_MOUSE ? | 1078 event_source_ == EVENT_SOURCE_MOUSE ? |
| 1073 views::Widget::MOVE_LOOP_SOURCE_MOUSE : | 1079 views::Widget::MOVE_LOOP_SOURCE_MOUSE : |
| 1074 views::Widget::MOVE_LOOP_SOURCE_TOUCH; | 1080 views::Widget::MOVE_LOOP_SOURCE_TOUCH; |
| 1075 const views::Widget::MoveLoopEscapeBehavior escape_behavior = | 1081 const views::Widget::MoveLoopEscapeBehavior escape_behavior = |
| 1076 is_dragging_new_browser_ ? | 1082 is_dragging_new_browser_ ? |
| 1077 views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE : | 1083 views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE : |
| 1078 views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE; | 1084 views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE; |
| 1079 views::Widget::MoveLoopResult result = | 1085 views::Widget::MoveLoopResult result = |
| 1080 move_loop_widget_->RunMoveLoop( | 1086 move_loop_widget_->RunMoveLoop( |
| 1081 drag_offset, move_loop_source, escape_behavior); | 1087 drag_offset, move_loop_source, escape_behavior); |
| 1082 content::NotificationService::current()->Notify( | 1088 content::NotificationService::current()->Notify( |
| 1083 chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, | 1089 chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, |
| 1084 content::NotificationService::AllBrowserContextsAndSources(), | 1090 content::NotificationService::AllBrowserContextsAndSources(), |
| 1085 content::NotificationService::NoDetails()); | 1091 content::NotificationService::NoDetails()); |
| 1086 | 1092 |
| 1087 if (!ref) | 1093 if (!ref) |
| 1088 return; | 1094 return; |
| 1089 // Under chromeos we immediately set the |move_loop_widget_| to NULL. | |
| 1090 if (move_loop_widget_) { | 1095 if (move_loop_widget_) { |
| 1091 move_loop_widget_->RemoveObserver(this); | 1096 move_loop_widget_->RemoveObserver(this); |
| 1092 move_loop_widget_ = NULL; | 1097 move_loop_widget_ = NULL; |
| 1093 } | 1098 } |
| 1094 is_dragging_window_ = false; | 1099 is_dragging_window_ = false; |
| 1095 waiting_for_run_loop_to_exit_ = false; | 1100 waiting_for_run_loop_to_exit_ = false; |
| 1096 if (end_run_loop_behavior_ == END_RUN_LOOP_CONTINUE_DRAGGING) { | 1101 if (end_run_loop_behavior_ == END_RUN_LOOP_CONTINUE_DRAGGING) { |
| 1097 end_run_loop_behavior_ = END_RUN_LOOP_STOP_DRAGGING; | 1102 end_run_loop_behavior_ = END_RUN_LOOP_STOP_DRAGGING; |
| 1098 if (tab_strip_to_attach_to_after_exit_) { | 1103 if (tab_strip_to_attach_to_after_exit_) { |
| 1099 gfx::Point point_in_screen(GetCursorScreenPoint()); | 1104 gfx::Point point_in_screen(GetCursorScreenPoint()); |
| (...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1780 it != browser_list->end(); ++it) { | 1785 it != browser_list->end(); ++it) { |
| 1781 if ((*it)->tab_strip_model()->empty()) | 1786 if ((*it)->tab_strip_model()->empty()) |
| 1782 exclude.insert((*it)->window()->GetNativeWindow()); | 1787 exclude.insert((*it)->window()->GetNativeWindow()); |
| 1783 } | 1788 } |
| 1784 #endif | 1789 #endif |
| 1785 return GetLocalProcessWindowAtPoint(host_desktop_type_, | 1790 return GetLocalProcessWindowAtPoint(host_desktop_type_, |
| 1786 screen_point, | 1791 screen_point, |
| 1787 exclude); | 1792 exclude); |
| 1788 | 1793 |
| 1789 } | 1794 } |
| OLD | NEW |