Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Unified Diff: ui/views/cocoa/bridged_native_widget.mm

Issue 1747803003: MacViews: Implement Tab Dragging (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Replace GCD with DelegateSimpleThread, remove ConstrainToEnclosingRect function, cleanup code. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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_);

Powered by Google App Engine
This is Rietveld 408576698