OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #import "ui/views/cocoa/bridged_native_widget.h" | 5 #import "ui/views/cocoa/bridged_native_widget.h" |
6 | 6 |
7 #import <objc/runtime.h> | 7 #import <objc/runtime.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
(...skipping 19 matching lines...) Expand all Loading... | |
30 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" | 30 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" |
31 #include "ui/views/view.h" | 31 #include "ui/views/view.h" |
32 #include "ui/views/views_delegate.h" | 32 #include "ui/views/views_delegate.h" |
33 #include "ui/views/widget/native_widget_mac.h" | 33 #include "ui/views/widget/native_widget_mac.h" |
34 #include "ui/views/widget/widget.h" | 34 #include "ui/views/widget/widget.h" |
35 #include "ui/views/widget/widget_aura_utils.h" | 35 #include "ui/views/widget/widget_aura_utils.h" |
36 #include "ui/views/widget/widget_delegate.h" | 36 #include "ui/views/widget/widget_delegate.h" |
37 | 37 |
38 extern "C" { | 38 extern "C" { |
39 | 39 |
40 typedef int32_t CGSWindow; | |
40 typedef int32_t CGSConnection; | 41 typedef int32_t CGSConnection; |
41 CGSConnection _CGSDefaultConnection(); | 42 CGSConnection _CGSDefaultConnection(); |
43 OSStatus CGSGetWindowBounds(CGSConnection connection, | |
44 CGSWindow window, | |
45 CGRect* bounds); | |
42 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, | 46 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, |
43 NSInteger windowNumber, | 47 NSInteger windowNumber, |
44 int radius); | 48 int radius); |
45 | 49 |
46 } | 50 } |
47 | 51 |
48 // The NSView that hosts the composited CALayer drawing the UI. It fills the | 52 // The NSView that hosts the composited CALayer drawing the UI. It fills the |
49 // window but is not hittable so that accessibility hit tests always go to the | 53 // window but is not hittable so that accessibility hit tests always go to the |
50 // BridgedContentView. | 54 // BridgedContentView. |
51 @interface ViewsCompositorSuperview : NSView | 55 @interface ViewsCompositorSuperview : NSView |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
608 } | 612 } |
609 | 613 |
610 void BridgedNativeWidget::ReleaseCapture() { | 614 void BridgedNativeWidget::ReleaseCapture() { |
611 mouse_capture_.reset(); | 615 mouse_capture_.reset(); |
612 } | 616 } |
613 | 617 |
614 bool BridgedNativeWidget::HasCapture() { | 618 bool BridgedNativeWidget::HasCapture() { |
615 return mouse_capture_ && mouse_capture_->IsActive(); | 619 return mouse_capture_ && mouse_capture_->IsActive(); |
616 } | 620 } |
617 | 621 |
622 Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop( | |
623 const gfx::Vector2d& drag_offset) { | |
624 DCHECK(!HasCapture()); | |
625 DCHECK(!window_move_loop_); | |
626 | |
627 // First, position the window in the right place. The point |drag_offset| | |
628 // away from the top-left corner needs to be positioned under the mouse. | |
629 // TODO(tapted): Figure out why the toolkit-views drag controller doesn't get | |
630 // this right when it first initializes the Widget. | |
631 gfx::Point mouse_in_screen = | |
632 display::Screen::GetScreen()->GetCursorScreenPoint(); | |
633 | |
634 // A window can't be moved vertically up out of the work area. Treat this case | |
635 // as if the mouse location is at the point it would be when the window first | |
636 // stopped moving. That is, vertically down such that the top edge of the | |
637 // window touches the menubar (or top of the screen in a dual-screen setup). | |
638 // Note on Mac we can assume that the y-coordinate of the work area origin is | |
639 // the bottom of the menu bar and not the Dock which doesn't affect window | |
640 // movement, but can reduce the work area on the bottom, left and right. | |
641 const display::Display display = | |
642 display::Screen::GetScreen()->GetDisplayNearestPoint(mouse_in_screen); | |
643 const int min_y = display.work_area().y() + drag_offset.y(); | |
644 if (mouse_in_screen.y() < min_y) | |
645 mouse_in_screen.set_y(min_y); | |
646 | |
647 gfx::Rect frame = gfx::ScreenRectFromNSRect([window_ frame]); | |
648 frame.set_x(mouse_in_screen.x() - drag_offset.x()); | |
649 frame.set_y(mouse_in_screen.y() - drag_offset.y()); | |
650 DCHECK_GE(frame.y(), display.work_area().y()); | |
651 | |
652 // After setting the frame to correct the initial offset, the drag controller | |
653 // may immediately want to quit when it's notified of the new bounds. So the | |
654 // MoveLoop must be set up before the call to setFrame. | |
655 window_move_loop_.reset(new CocoaWindowMoveLoop(this, mouse_in_screen)); | |
656 | |
657 const NSRect ns_frame = gfx::ScreenRectToNSRect(frame); | |
658 [window_ setFrame:ns_frame display:YES animate:NO]; | |
659 | |
660 // Setting the frame will call OnWidgetBoundsChanged(), which could result in | |
661 // a call to EndMoveLoop(). | |
662 if (!window_move_loop_) | |
663 return Widget::MOVE_LOOP_SUCCESSFUL; | |
664 | |
665 // Make sure WindowServer has caught up with moving the window, this is | |
666 // required in order to send the MouseDown click to the intended position. | |
667 // El Capitan would always replicate the old window coordinates when calling | |
668 // CGSGetWindowBounds(). | |
669 // DetachToBrowserTabDragControllerTest.MacDetachesAndReattachesSecondTab will | |
670 // fail without the following NSRunLoop pass. | |
671 [[NSRunLoop currentRunLoop] | |
tapted
2016/05/23 07:29:28
is this still needed?
themblsha
2016/05/26 15:13:25
Nope, removed.
| |
672 runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]]; | |
673 DCHECK(NSEqualRects(ns_frame, WindowServerFrame())); | |
674 | |
675 return window_move_loop_->Run(); | |
676 | |
677 // |this| may be destroyed during the RunLoop, causing it to exit early. | |
678 // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by | |
679 // calling EndMoveLoop(). So window_move_loop_ will always be null before the | |
680 // function returns. But don't DCHECK since |this| might not be valid. | |
681 } | |
682 | |
683 void BridgedNativeWidget::EndMoveLoop() { | |
684 DCHECK(window_move_loop_); | |
685 window_move_loop_->End(); | |
686 window_move_loop_.reset(); | |
687 } | |
688 | |
689 bool BridgedNativeWidget::IsRunMoveLoopActive() const { | |
690 return window_move_loop_.get(); | |
691 } | |
692 | |
618 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, | 693 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, |
619 void* value) { | 694 void* value) { |
620 NSString* key = [NSString stringWithUTF8String:name]; | 695 NSString* key = [NSString stringWithUTF8String:name]; |
621 if (value) { | 696 if (value) { |
622 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] | 697 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] |
623 forKey:key]; | 698 forKey:key]; |
624 } else { | 699 } else { |
625 [GetWindowProperties() removeObjectForKey:key]; | 700 [GetWindowProperties() removeObjectForKey:key]; |
626 } | 701 } |
627 } | 702 } |
628 | 703 |
629 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { | 704 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { |
630 NSString* key = [NSString stringWithUTF8String:name]; | 705 NSString* key = [NSString stringWithUTF8String:name]; |
631 return [[GetWindowProperties() objectForKey:key] pointerValue]; | 706 return [[GetWindowProperties() objectForKey:key] pointerValue]; |
632 } | 707 } |
633 | 708 |
634 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { | 709 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { |
635 [window_delegate_ setCursor:cursor]; | 710 [window_delegate_ setCursor:cursor]; |
636 } | 711 } |
637 | 712 |
638 void BridgedNativeWidget::OnWindowWillClose() { | 713 void BridgedNativeWidget::OnWindowWillClose() { |
714 DCHECK(!drag_run_loop_); | |
639 if (parent_) { | 715 if (parent_) { |
640 parent_->RemoveChildWindow(this); | 716 parent_->RemoveChildWindow(this); |
641 parent_ = nullptr; | 717 parent_ = nullptr; |
642 } | 718 } |
643 [window_ setDelegate:nil]; | 719 [window_ setDelegate:nil]; |
644 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; | 720 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
645 native_widget_mac_->OnWindowWillClose(); | 721 native_widget_mac_->OnWindowWillClose(); |
646 } | 722 } |
647 | 723 |
648 void BridgedNativeWidget::OnFullscreenTransitionStart( | 724 void BridgedNativeWidget::OnFullscreenTransitionStart( |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 | 802 |
727 // 10.9 is unable to generate a window shadow from the composited CALayer, so | 803 // 10.9 is unable to generate a window shadow from the composited CALayer, so |
728 // use Quartz. | 804 // use Quartz. |
729 // We don't update the window mask during a live resize, instead it is done | 805 // We don't update the window mask during a live resize, instead it is done |
730 // after the resize is completed in viewDidEndLiveResize: in | 806 // after the resize is completed in viewDidEndLiveResize: in |
731 // BridgedContentView. | 807 // BridgedContentView. |
732 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) | 808 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) |
733 [bridged_view_ updateWindowMask]; | 809 [bridged_view_ updateWindowMask]; |
734 } | 810 } |
735 | 811 |
812 void BridgedNativeWidget::OnPositionChanged() { | |
813 native_widget_mac_->GetWidget()->OnNativeWidgetMove(); | |
814 } | |
815 | |
736 void BridgedNativeWidget::OnVisibilityChanged() { | 816 void BridgedNativeWidget::OnVisibilityChanged() { |
737 OnVisibilityChangedTo([window_ isVisible]); | 817 OnVisibilityChangedTo([window_ isVisible]); |
738 } | 818 } |
739 | 819 |
740 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { | 820 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
741 if (window_visible_ == new_visibility) | 821 if (window_visible_ == new_visibility) |
742 return; | 822 return; |
743 | 823 |
744 window_visible_ = new_visibility; | 824 window_visible_ = new_visibility; |
745 | 825 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
882 return input_method_.get(); | 962 return input_method_.get(); |
883 } | 963 } |
884 | 964 |
885 gfx::Rect BridgedNativeWidget::GetRestoredBounds() const { | 965 gfx::Rect BridgedNativeWidget::GetRestoredBounds() const { |
886 if (target_fullscreen_state_ || in_fullscreen_transition_) | 966 if (target_fullscreen_state_ || in_fullscreen_transition_) |
887 return bounds_before_fullscreen_; | 967 return bounds_before_fullscreen_; |
888 | 968 |
889 return gfx::ScreenRectFromNSRect([window_ frame]); | 969 return gfx::ScreenRectFromNSRect([window_ frame]); |
890 } | 970 } |
891 | 971 |
972 NSRect BridgedNativeWidget::WindowServerFrame() const { | |
973 CGRect bounds = NSZeroRect; | |
974 CGSGetWindowBounds(_CGSDefaultConnection(), [window_ windowNumber], | |
975 &bounds); | |
976 NSRect rect = ScreenRectToNSRect(gfx::Rect(bounds)); | |
977 rect.size = [window_ frame].size; | |
978 return rect; | |
979 } | |
980 | |
892 void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type, | 981 void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type, |
893 bool translucent) { | 982 bool translucent) { |
894 DCHECK(bridged_view_); | 983 DCHECK(bridged_view_); |
895 DCHECK(!layer()); | 984 DCHECK(!layer()); |
896 | 985 |
897 CreateCompositor(); | 986 CreateCompositor(); |
898 DCHECK(compositor_); | 987 DCHECK(compositor_); |
899 | 988 |
900 SetLayer(new ui::Layer(layer_type)); | 989 SetLayer(new ui::Layer(layer_type)); |
901 // Note, except for controls, this will set the layer to be hidden, since it | 990 // Note, except for controls, this will set the layer to be hidden, since it |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1303 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1392 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
1304 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1393 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
1305 // changes. Previously we tried adding an NSView and removing it, but for some | 1394 // changes. Previously we tried adding an NSView and removing it, but for some |
1306 // reason it required reposting the mouse-down event, and didn't always work. | 1395 // reason it required reposting the mouse-down event, and didn't always work. |
1307 // Calling the below seems to be an effective solution. | 1396 // Calling the below seems to be an effective solution. |
1308 [window_ setMovableByWindowBackground:NO]; | 1397 [window_ setMovableByWindowBackground:NO]; |
1309 [window_ setMovableByWindowBackground:YES]; | 1398 [window_ setMovableByWindowBackground:YES]; |
1310 } | 1399 } |
1311 | 1400 |
1312 } // namespace views | 1401 } // namespace views |
OLD | NEW |