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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 NSInteger event_number = [ns_event eventNumber]; | 200 NSInteger event_number = [ns_event eventNumber]; |
197 | 201 |
198 // The logic here is a bit convoluted because we want to mitigate race | 202 // The logic here is a bit convoluted because we want to mitigate race |
199 // conditions if somehow a different mouse-down occurs between reposts. | 203 // conditions if somehow a different mouse-down occurs between reposts. |
200 // Specifically, we want to avoid: | 204 // Specifically, we want to avoid: |
201 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is | 205 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is |
202 // draggable outside of a repost cycle), | 206 // draggable outside of a repost cycle), |
203 // - any repost loop. | 207 // - any repost loop. |
204 | 208 |
205 if (repost_state == NONE) { | 209 if (repost_state == NONE) { |
| 210 if (CGEventGetIntegerValueField([ns_event CGEvent], |
| 211 kCGEventSourceUserData) == |
| 212 views::CocoaWindowMoveLoop:: |
| 213 kCocoaWindowMoveLoopSimulatedEventUserData) { |
| 214 return ns_event; |
| 215 } |
| 216 |
206 if (WindowWantsMouseDownReposted(ns_event)) { | 217 if (WindowWantsMouseDownReposted(ns_event)) { |
207 repost_state = EXPECTING_REPOST; | 218 repost_state = EXPECTING_REPOST; |
208 reposted_event_number = event_number; | 219 reposted_event_number = event_number; |
209 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); | 220 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); |
210 return nil; | 221 return nil; |
211 } | 222 } |
212 | 223 |
213 return ns_event; | 224 return ns_event; |
214 } | 225 } |
215 | 226 |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 } | 619 } |
609 | 620 |
610 void BridgedNativeWidget::ReleaseCapture() { | 621 void BridgedNativeWidget::ReleaseCapture() { |
611 mouse_capture_.reset(); | 622 mouse_capture_.reset(); |
612 } | 623 } |
613 | 624 |
614 bool BridgedNativeWidget::HasCapture() { | 625 bool BridgedNativeWidget::HasCapture() { |
615 return mouse_capture_ && mouse_capture_->IsActive(); | 626 return mouse_capture_ && mouse_capture_->IsActive(); |
616 } | 627 } |
617 | 628 |
| 629 Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop( |
| 630 const gfx::Vector2d& drag_offset) { |
| 631 DCHECK(!HasCapture()); |
| 632 DCHECK(!window_move_loop_); |
| 633 |
| 634 // First, position the window in the right place. The point |drag_offset| |
| 635 // away from the top-left corner needs to be positioned under the mouse. |
| 636 // TODO(tapted): Figure out why the toolkit-views drag controller doesn't get |
| 637 // this right when it first initializes the Widget. |
| 638 gfx::Point mouse_in_screen = gfx::Screen::GetScreen()->GetCursorScreenPoint(); |
| 639 |
| 640 // A window can't be moved vertically up out of the work area. Treat this case |
| 641 // as if the mouse location is at the point it would be when the window first |
| 642 // stopped moving. That is, vertically down such that the top edge of the |
| 643 // window touches the menubar (or top of the screen in a dual-screen setup). |
| 644 // Note on Mac we can assume that the y-coordinate of the work area origin is |
| 645 // the bottom of the menu bar and not the Dock which doesn't affect window |
| 646 // movement, but can reduce the work area on the bottom, left and right. |
| 647 const gfx::Display display = |
| 648 gfx::Screen::GetScreen()->GetDisplayNearestPoint(mouse_in_screen); |
| 649 const int min_y = display.work_area().y() + drag_offset.y(); |
| 650 if (mouse_in_screen.y() < min_y) |
| 651 mouse_in_screen.set_y(min_y); |
| 652 |
| 653 gfx::Rect frame = gfx::ScreenRectFromNSRect([window_ frame]); |
| 654 frame.set_x(mouse_in_screen.x() - drag_offset.x()); |
| 655 frame.set_y(mouse_in_screen.y() - drag_offset.y()); |
| 656 DCHECK_GE(frame.y(), display.work_area().y()); |
| 657 |
| 658 // After setting the frame to correct the initial offset, the drag controller |
| 659 // may immediately want to quit when it's notified of the new bounds. So the |
| 660 // MoveLoop must be set up before the call to setFrame. |
| 661 window_move_loop_.reset(new CocoaWindowMoveLoop(this, mouse_in_screen)); |
| 662 |
| 663 const NSRect ns_frame = gfx::ScreenRectToNSRect(frame); |
| 664 [window_ setFrame:ns_frame display:YES animate:NO]; |
| 665 |
| 666 // Setting the frame will call OnWidgetBoundsChanged(), which could result in |
| 667 // a call to EndMoveLoop(). |
| 668 if (!window_move_loop_) |
| 669 return Widget::MOVE_LOOP_SUCCESSFUL; |
| 670 |
| 671 // Make sure WindowServer has caught up with moving the window, this is |
| 672 // required in order to send the MouseDown click to the intended position. |
| 673 // El Capitan would always replicate the old window coordinates when calling |
| 674 // CGSGetWindowBounds(). |
| 675 // DetachToBrowserTabDragControllerTest.MacDetachesAndReattachesSecondTab will |
| 676 // fail without the following NSRunLoop pass. |
| 677 [[NSRunLoop currentRunLoop] |
| 678 runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]]; |
| 679 DCHECK(NSEqualRects(ns_frame, WindowServerFrame())); |
| 680 |
| 681 return window_move_loop_->Run(); |
| 682 |
| 683 // |this| may be destroyed during the RunLoop, causing it to exit early. |
| 684 // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by |
| 685 // calling EndMoveLoop(). So window_move_loop_ will always be null before the |
| 686 // function returns. But don't DCHECK since |this| might not be valid. |
| 687 } |
| 688 |
| 689 void BridgedNativeWidget::EndMoveLoop() { |
| 690 DCHECK(window_move_loop_); |
| 691 window_move_loop_->End(); |
| 692 window_move_loop_.reset(); |
| 693 } |
| 694 |
| 695 bool BridgedNativeWidget::IsRunMoveLoopActive() const { |
| 696 return window_move_loop_.get(); |
| 697 } |
| 698 |
618 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, | 699 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, |
619 void* value) { | 700 void* value) { |
620 NSString* key = [NSString stringWithUTF8String:name]; | 701 NSString* key = [NSString stringWithUTF8String:name]; |
621 if (value) { | 702 if (value) { |
622 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] | 703 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] |
623 forKey:key]; | 704 forKey:key]; |
624 } else { | 705 } else { |
625 [GetWindowProperties() removeObjectForKey:key]; | 706 [GetWindowProperties() removeObjectForKey:key]; |
626 } | 707 } |
627 } | 708 } |
628 | 709 |
629 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { | 710 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { |
630 NSString* key = [NSString stringWithUTF8String:name]; | 711 NSString* key = [NSString stringWithUTF8String:name]; |
631 return [[GetWindowProperties() objectForKey:key] pointerValue]; | 712 return [[GetWindowProperties() objectForKey:key] pointerValue]; |
632 } | 713 } |
633 | 714 |
634 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { | 715 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { |
635 [window_delegate_ setCursor:cursor]; | 716 [window_delegate_ setCursor:cursor]; |
636 } | 717 } |
637 | 718 |
638 void BridgedNativeWidget::OnWindowWillClose() { | 719 void BridgedNativeWidget::OnWindowWillClose() { |
| 720 DCHECK(!drag_run_loop_); |
639 if (parent_) { | 721 if (parent_) { |
640 parent_->RemoveChildWindow(this); | 722 parent_->RemoveChildWindow(this); |
641 parent_ = nullptr; | 723 parent_ = nullptr; |
642 } | 724 } |
643 [window_ setDelegate:nil]; | 725 [window_ setDelegate:nil]; |
644 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; | 726 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
645 native_widget_mac_->OnWindowWillClose(); | 727 native_widget_mac_->OnWindowWillClose(); |
646 } | 728 } |
647 | 729 |
648 void BridgedNativeWidget::OnFullscreenTransitionStart( | 730 void BridgedNativeWidget::OnFullscreenTransitionStart( |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 | 808 |
727 // 10.9 is unable to generate a window shadow from the composited CALayer, so | 809 // 10.9 is unable to generate a window shadow from the composited CALayer, so |
728 // use Quartz. | 810 // use Quartz. |
729 // We don't update the window mask during a live resize, instead it is done | 811 // We don't update the window mask during a live resize, instead it is done |
730 // after the resize is completed in viewDidEndLiveResize: in | 812 // after the resize is completed in viewDidEndLiveResize: in |
731 // BridgedContentView. | 813 // BridgedContentView. |
732 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) | 814 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) |
733 [bridged_view_ updateWindowMask]; | 815 [bridged_view_ updateWindowMask]; |
734 } | 816 } |
735 | 817 |
| 818 void BridgedNativeWidget::OnPositionChanged() { |
| 819 native_widget_mac_->GetWidget()->OnNativeWidgetMove(); |
| 820 } |
| 821 |
736 void BridgedNativeWidget::OnVisibilityChanged() { | 822 void BridgedNativeWidget::OnVisibilityChanged() { |
737 OnVisibilityChangedTo([window_ isVisible]); | 823 OnVisibilityChangedTo([window_ isVisible]); |
738 } | 824 } |
739 | 825 |
740 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { | 826 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
741 if (window_visible_ == new_visibility) | 827 if (window_visible_ == new_visibility) |
742 return; | 828 return; |
743 | 829 |
744 window_visible_ = new_visibility; | 830 window_visible_ = new_visibility; |
745 | 831 |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 return input_method_.get(); | 965 return input_method_.get(); |
880 } | 966 } |
881 | 967 |
882 gfx::Rect BridgedNativeWidget::GetRestoredBounds() const { | 968 gfx::Rect BridgedNativeWidget::GetRestoredBounds() const { |
883 if (target_fullscreen_state_ || in_fullscreen_transition_) | 969 if (target_fullscreen_state_ || in_fullscreen_transition_) |
884 return bounds_before_fullscreen_; | 970 return bounds_before_fullscreen_; |
885 | 971 |
886 return gfx::ScreenRectFromNSRect([window_ frame]); | 972 return gfx::ScreenRectFromNSRect([window_ frame]); |
887 } | 973 } |
888 | 974 |
| 975 NSRect BridgedNativeWidget::WindowServerFrame() const { |
| 976 CGRect bounds = NSZeroRect; |
| 977 CGSGetWindowBounds(_CGSDefaultConnection(), [window_ windowNumber], |
| 978 &bounds); |
| 979 NSRect rect = ScreenRectToNSRect(gfx::Rect(bounds)); |
| 980 rect.size = [window_ frame].size; |
| 981 return rect; |
| 982 } |
| 983 |
889 void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type, | 984 void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type, |
890 bool translucent) { | 985 bool translucent) { |
891 DCHECK(bridged_view_); | 986 DCHECK(bridged_view_); |
892 DCHECK(!layer()); | 987 DCHECK(!layer()); |
893 | 988 |
894 CreateCompositor(); | 989 CreateCompositor(); |
895 DCHECK(compositor_); | 990 DCHECK(compositor_); |
896 | 991 |
897 SetLayer(new ui::Layer(layer_type)); | 992 SetLayer(new ui::Layer(layer_type)); |
898 // Note, except for controls, this will set the layer to be hidden, since it | 993 // 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... |
1300 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1395 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
1301 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1396 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
1302 // changes. Previously we tried adding an NSView and removing it, but for some | 1397 // changes. Previously we tried adding an NSView and removing it, but for some |
1303 // reason it required reposting the mouse-down event, and didn't always work. | 1398 // reason it required reposting the mouse-down event, and didn't always work. |
1304 // Calling the below seems to be an effective solution. | 1399 // Calling the below seems to be an effective solution. |
1305 [window_ setMovableByWindowBackground:NO]; | 1400 [window_ setMovableByWindowBackground:NO]; |
1306 [window_ setMovableByWindowBackground:YES]; | 1401 [window_ setMovableByWindowBackground:YES]; |
1307 } | 1402 } |
1308 | 1403 |
1309 } // namespace views | 1404 } // namespace views |
OLD | NEW |