| 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 0ccff9d15a0fd3402ed9c1e613f6552cd7de2f62..d701b765ab7878552b4ede6103174715ab7bd77f 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);
|
| @@ -203,6 +207,13 @@ NSEvent* RepostEventIfHandledByWindow(NSEvent* ns_event) {
|
| // - any repost loop.
|
|
|
| if (repost_state == NONE) {
|
| + if (CGEventGetIntegerValueField([ns_event CGEvent],
|
| + kCGEventSourceUserData) ==
|
| + views::CocoaWindowMoveLoop::
|
| + kCocoaWindowMoveLoopSimulatedEventUserData) {
|
| + return ns_event;
|
| + }
|
| +
|
| if (WindowWantsMouseDownReposted(ns_event)) {
|
| repost_state = EXPECTING_REPOST;
|
| reposted_event_number = event_number;
|
| @@ -615,6 +626,76 @@ 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 = gfx::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 gfx::Display display =
|
| + gfx::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]
|
| + 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 +717,7 @@ void BridgedNativeWidget::SetCursor(NSCursor* cursor) {
|
| }
|
|
|
| void BridgedNativeWidget::OnWindowWillClose() {
|
| + DCHECK(!drag_run_loop_);
|
| if (parent_) {
|
| parent_->RemoveChildWindow(this);
|
| parent_ = nullptr;
|
| @@ -733,6 +815,10 @@ void BridgedNativeWidget::OnSizeChanged() {
|
| [bridged_view_ updateWindowMask];
|
| }
|
|
|
| +void BridgedNativeWidget::OnPositionChanged() {
|
| + native_widget_mac_->GetWidget()->OnNativeWidgetMove();
|
| +}
|
| +
|
| void BridgedNativeWidget::OnVisibilityChanged() {
|
| OnVisibilityChangedTo([window_ isVisible]);
|
| }
|
| @@ -886,6 +972,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_);
|
|
|