Chromium Code Reviews| Index: ui/views/cocoa/bridged_native_widget.mm | 
| diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm | 
| index 1c9560f2e8834aeb19225abd760819145854b361..29eb700f467f986ab33d6dcfd95c3bc80fdb44d3 100644 | 
| --- a/ui/views/cocoa/bridged_native_widget.mm | 
| +++ b/ui/views/cocoa/bridged_native_widget.mm | 
| @@ -37,8 +37,12 @@ | 
| extern "C" { | 
| +typedef int32_t CGSWindow; | 
| typedef int32_t CGSConnection; | 
| CGSConnection _CGSDefaultConnection(); | 
| +OSStatus CGSGetWindowBounds(CGSConnection connection, | 
| + CGSWindow window, | 
| + CGRect* bounds); | 
| CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, | 
| NSInteger windowNumber, | 
| int radius); | 
| @@ -615,6 +619,77 @@ bool BridgedNativeWidget::HasCapture() { | 
| return mouse_capture_ && mouse_capture_->IsActive(); | 
| } | 
| +Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop( | 
| + const gfx::Vector2d& drag_offset) { | 
| + DCHECK(!HasCapture()); | 
| + DCHECK(!window_move_loop_); | 
| + | 
| + // First, position the window in the right place. The point |drag_offset| | 
| + // away from the top-left corner needs to be positioned under the mouse. | 
| + // TODO(tapted): Figure out why the toolkit-views drag controller doesn't get | 
| + // this right when it first initializes the Widget. | 
| + gfx::Point mouse_in_screen = | 
| + display::Screen::GetScreen()->GetCursorScreenPoint(); | 
| + | 
| + // A window can't be moved vertically up out of the work area. Treat this case | 
| + // as if the mouse location is at the point it would be when the window first | 
| + // stopped moving. That is, vertically down such that the top edge of the | 
| + // window touches the menubar (or top of the screen in a dual-screen setup). | 
| + // Note on Mac we can assume that the y-coordinate of the work area origin is | 
| + // the bottom of the menu bar and not the Dock which doesn't affect window | 
| + // movement, but can reduce the work area on the bottom, left and right. | 
| + const display::Display display = | 
| + display::Screen::GetScreen()->GetDisplayNearestPoint(mouse_in_screen); | 
| + const int min_y = display.work_area().y() + drag_offset.y(); | 
| + if (mouse_in_screen.y() < min_y) | 
| + mouse_in_screen.set_y(min_y); | 
| + | 
| + gfx::Rect frame = gfx::ScreenRectFromNSRect([window_ frame]); | 
| + frame.set_x(mouse_in_screen.x() - drag_offset.x()); | 
| + frame.set_y(mouse_in_screen.y() - drag_offset.y()); | 
| + DCHECK_GE(frame.y(), display.work_area().y()); | 
| + | 
| + // After setting the frame to correct the initial offset, the drag controller | 
| + // may immediately want to quit when it's notified of the new bounds. So the | 
| + // MoveLoop must be set up before the call to setFrame. | 
| + window_move_loop_.reset(new CocoaWindowMoveLoop(this, mouse_in_screen)); | 
| + | 
| + const NSRect ns_frame = gfx::ScreenRectToNSRect(frame); | 
| + [window_ setFrame:ns_frame display:YES animate:NO]; | 
| + | 
| + // Setting the frame will call OnWidgetBoundsChanged(), which could result in | 
| + // a call to EndMoveLoop(). | 
| + if (!window_move_loop_) | 
| + return Widget::MOVE_LOOP_SUCCESSFUL; | 
| + | 
| + // Make sure WindowServer has caught up with moving the window, this is | 
| + // required in order to send the MouseDown click to the intended position. | 
| + // El Capitan would always replicate the old window coordinates when calling | 
| + // CGSGetWindowBounds(). | 
| + // DetachToBrowserTabDragControllerTest.MacDetachesAndReattachesSecondTab will | 
| + // fail without the following NSRunLoop pass. | 
| + [[NSRunLoop currentRunLoop] | 
| 
 
tapted
2016/05/23 07:29:28
is this still needed?
 
themblsha
2016/05/26 15:13:25
Nope, removed.
 
 | 
| + runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]]; | 
| + DCHECK(NSEqualRects(ns_frame, WindowServerFrame())); | 
| + | 
| + return window_move_loop_->Run(); | 
| + | 
| + // |this| may be destroyed during the RunLoop, causing it to exit early. | 
| + // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by | 
| + // calling EndMoveLoop(). So window_move_loop_ will always be null before the | 
| + // function returns. But don't DCHECK since |this| might not be valid. | 
| +} | 
| + | 
| +void BridgedNativeWidget::EndMoveLoop() { | 
| + DCHECK(window_move_loop_); | 
| + window_move_loop_->End(); | 
| + window_move_loop_.reset(); | 
| +} | 
| + | 
| +bool BridgedNativeWidget::IsRunMoveLoopActive() const { | 
| + return window_move_loop_.get(); | 
| +} | 
| + | 
| void BridgedNativeWidget::SetNativeWindowProperty(const char* name, | 
| void* value) { | 
| NSString* key = [NSString stringWithUTF8String:name]; | 
| @@ -636,6 +711,7 @@ void BridgedNativeWidget::SetCursor(NSCursor* cursor) { | 
| } | 
| void BridgedNativeWidget::OnWindowWillClose() { | 
| + DCHECK(!drag_run_loop_); | 
| if (parent_) { | 
| parent_->RemoveChildWindow(this); | 
| parent_ = nullptr; | 
| @@ -733,6 +809,10 @@ void BridgedNativeWidget::OnSizeChanged() { | 
| [bridged_view_ updateWindowMask]; | 
| } | 
| +void BridgedNativeWidget::OnPositionChanged() { | 
| + native_widget_mac_->GetWidget()->OnNativeWidgetMove(); | 
| +} | 
| + | 
| void BridgedNativeWidget::OnVisibilityChanged() { | 
| OnVisibilityChangedTo([window_ isVisible]); | 
| } | 
| @@ -889,6 +969,15 @@ gfx::Rect BridgedNativeWidget::GetRestoredBounds() const { | 
| return gfx::ScreenRectFromNSRect([window_ frame]); | 
| } | 
| +NSRect BridgedNativeWidget::WindowServerFrame() const { | 
| + CGRect bounds = NSZeroRect; | 
| + CGSGetWindowBounds(_CGSDefaultConnection(), [window_ windowNumber], | 
| + &bounds); | 
| + NSRect rect = ScreenRectToNSRect(gfx::Rect(bounds)); | 
| + rect.size = [window_ frame].size; | 
| + return rect; | 
| +} | 
| + | 
| void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type, | 
| bool translucent) { | 
| DCHECK(bridged_view_); |