| 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 17 matching lines...) Expand all Loading... |
| 28 #include "ui/views/cocoa/tooltip_manager_mac.h" | 28 #include "ui/views/cocoa/tooltip_manager_mac.h" |
| 29 #import "ui/views/cocoa/views_nswindow_delegate.h" | 29 #import "ui/views/cocoa/views_nswindow_delegate.h" |
| 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" { | |
| 39 | |
| 40 typedef int32_t CGSConnection; | |
| 41 CGSConnection _CGSDefaultConnection(); | |
| 42 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, | |
| 43 NSInteger windowNumber, | |
| 44 int radius); | |
| 45 | |
| 46 } | |
| 47 | |
| 48 // The NSView that hosts the composited CALayer drawing the UI. It fills the | 38 // 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 | 39 // window but is not hittable so that accessibility hit tests always go to the |
| 50 // BridgedContentView. | 40 // BridgedContentView. |
| 51 @interface ViewsCompositorSuperview : NSView | 41 @interface ViewsCompositorSuperview : NSView |
| 52 @end | 42 @end |
| 53 | 43 |
| 54 @implementation ViewsCompositorSuperview | 44 @implementation ViewsCompositorSuperview |
| 55 - (NSView*)hitTest:(NSPoint)aPoint { | 45 - (NSView*)hitTest:(NSPoint)aPoint { |
| 56 return nil; | 46 return nil; |
| 57 } | 47 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 const CGFloat kYosemiteMenuOpacity = 177.0 / 255.0; | 89 const CGFloat kYosemiteMenuOpacity = 177.0 / 255.0; |
| 100 const int kYosemiteMenuBlur = 80; | 90 const int kYosemiteMenuBlur = 80; |
| 101 | 91 |
| 102 // Margin at edge and corners of the window that trigger resizing. These match | 92 // Margin at edge and corners of the window that trigger resizing. These match |
| 103 // actual Cocoa resize margins. | 93 // actual Cocoa resize margins. |
| 104 const int kResizeAreaEdgeSize = 3; | 94 const int kResizeAreaEdgeSize = 3; |
| 105 const int kResizeAreaCornerSize = 12; | 95 const int kResizeAreaCornerSize = 12; |
| 106 | 96 |
| 107 int kWindowPropertiesKey; | 97 int kWindowPropertiesKey; |
| 108 | 98 |
| 99 bool g_ignore_next_mouse_down_for_draggable_regions = false; |
| 100 |
| 109 float GetDeviceScaleFactorFromView(NSView* view) { | 101 float GetDeviceScaleFactorFromView(NSView* view) { |
| 110 gfx::Display display = | 102 gfx::Display display = |
| 111 gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); | 103 gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); |
| 112 DCHECK(display.is_valid()); | 104 DCHECK(display.is_valid()); |
| 113 return display.device_scale_factor(); | 105 return display.device_scale_factor(); |
| 114 } | 106 } |
| 115 | 107 |
| 116 // Returns true if bounds passed to window in SetBounds should be treated as | 108 // Returns true if bounds passed to window in SetBounds should be treated as |
| 117 // though they are in screen coordinates. | 109 // though they are in screen coordinates. |
| 118 bool PositionWindowInScreenCoordinates(views::Widget* widget, | 110 bool PositionWindowInScreenCoordinates(views::Widget* widget, |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 NSInteger event_number = [ns_event eventNumber]; | 188 NSInteger event_number = [ns_event eventNumber]; |
| 197 | 189 |
| 198 // The logic here is a bit convoluted because we want to mitigate race | 190 // The logic here is a bit convoluted because we want to mitigate race |
| 199 // conditions if somehow a different mouse-down occurs between reposts. | 191 // conditions if somehow a different mouse-down occurs between reposts. |
| 200 // Specifically, we want to avoid: | 192 // Specifically, we want to avoid: |
| 201 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is | 193 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is |
| 202 // draggable outside of a repost cycle), | 194 // draggable outside of a repost cycle), |
| 203 // - any repost loop. | 195 // - any repost loop. |
| 204 | 196 |
| 205 if (repost_state == NONE) { | 197 if (repost_state == NONE) { |
| 198 if (g_ignore_next_mouse_down_for_draggable_regions) { |
| 199 g_ignore_next_mouse_down_for_draggable_regions = false; |
| 200 return ns_event; |
| 201 } |
| 202 |
| 206 if (WindowWantsMouseDownReposted(ns_event)) { | 203 if (WindowWantsMouseDownReposted(ns_event)) { |
| 207 repost_state = EXPECTING_REPOST; | 204 repost_state = EXPECTING_REPOST; |
| 208 reposted_event_number = event_number; | 205 reposted_event_number = event_number; |
| 209 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); | 206 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); |
| 210 return nil; | 207 return nil; |
| 211 } | 208 } |
| 212 | 209 |
| 213 return ns_event; | 210 return ns_event; |
| 214 } | 211 } |
| 215 | 212 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 return left_rank->second < right_rank->second ? NSOrderedAscending | 301 return left_rank->second < right_rank->second ? NSOrderedAscending |
| 305 : NSOrderedDescending; | 302 : NSOrderedDescending; |
| 306 } | 303 } |
| 307 | 304 |
| 308 // If both are unassociated, consider that order is not important | 305 // If both are unassociated, consider that order is not important |
| 309 return NSOrderedSame; | 306 return NSOrderedSame; |
| 310 } | 307 } |
| 311 | 308 |
| 312 } // namespace | 309 } // namespace |
| 313 | 310 |
| 311 extern "C" { |
| 312 |
| 313 typedef int32_t CGSConnection; |
| 314 CGSConnection _CGSDefaultConnection(); |
| 315 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, |
| 316 NSInteger windowNumber, |
| 317 int radius); |
| 318 } |
| 319 |
| 314 namespace views { | 320 namespace views { |
| 315 | 321 |
| 316 // static | 322 // static |
| 317 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( | 323 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( |
| 318 NSWindow* window, | 324 NSWindow* window, |
| 319 const gfx::Size& content_size) { | 325 const gfx::Size& content_size) { |
| 320 NSRect content_rect = | 326 NSRect content_rect = |
| 321 NSMakeRect(0, 0, content_size.width(), content_size.height()); | 327 NSMakeRect(0, 0, content_size.width(), content_size.height()); |
| 322 NSRect frame_rect = [window frameRectForContentRect:content_rect]; | 328 NSRect frame_rect = [window frameRectForContentRect:content_rect]; |
| 323 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); | 329 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 } | 614 } |
| 609 | 615 |
| 610 void BridgedNativeWidget::ReleaseCapture() { | 616 void BridgedNativeWidget::ReleaseCapture() { |
| 611 mouse_capture_.reset(); | 617 mouse_capture_.reset(); |
| 612 } | 618 } |
| 613 | 619 |
| 614 bool BridgedNativeWidget::HasCapture() { | 620 bool BridgedNativeWidget::HasCapture() { |
| 615 return mouse_capture_ && mouse_capture_->IsActive(); | 621 return mouse_capture_ && mouse_capture_->IsActive(); |
| 616 } | 622 } |
| 617 | 623 |
| 624 Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop( |
| 625 const gfx::Vector2d& drag_offset) { |
| 626 DCHECK(!HasCapture()); |
| 627 DCHECK(!window_move_loop_); |
| 628 |
| 629 // First, position the window in the right place. The point |drag_offset| |
| 630 // away from the top-left corner needs to be positioned under the mouse. |
| 631 // TODO(tapted): Figure out why the toolkit-views drag controller doesn't get |
| 632 // this right when it first initializes the Widget. |
| 633 gfx::Point mouse_in_screen = gfx::Screen::GetScreen()->GetCursorScreenPoint(); |
| 634 |
| 635 // A window can't be moved vertically up out of the work area. Treat this case |
| 636 // as if the mouse location is at the point it would be when the window first |
| 637 // stopped moving. That is, vertically down such that the top edge of the |
| 638 // window touches the menubar (or top of the screen in a dual-screen setup). |
| 639 // Note on Mac we can assume that the y-coordinate of the work area origin is |
| 640 // the bottom of the menu bar and not the Dock which doesn't affect window |
| 641 // movement, but can reduce the work area on the bottom, left and right. |
| 642 const gfx::Display display = |
| 643 gfx::Screen::GetScreen()->GetDisplayNearestPoint(mouse_in_screen); |
| 644 int min_y = display.work_area().y() + drag_offset.y(); |
| 645 if (mouse_in_screen.y() < min_y) |
| 646 mouse_in_screen.set_y(min_y); |
| 647 |
| 648 gfx::Rect frame = gfx::ScreenRectFromNSRect([window_ frame]); |
| 649 frame.set_x(mouse_in_screen.x() - drag_offset.x()); |
| 650 frame.set_y(mouse_in_screen.y() - drag_offset.y()); |
| 651 DCHECK_GE(frame.y(), display.work_area().y()); |
| 652 |
| 653 // After setting the frame to correct the initial offset, the drag controller |
| 654 // may immediately want to quit when it's notified of the new bounds. So the |
| 655 // MoveLoop must be set up before the call to setFrame. |
| 656 window_move_loop_.reset(new CocoaWindowMoveLoop(this, mouse_in_screen)); |
| 657 |
| 658 // Animating may provide a less janky UX, but something custom would be |
| 659 // required so that it follows updates to the mouse position. |
| 660 const NSRect ns_frame = gfx::ScreenRectToNSRect(frame); |
| 661 [window_ setFrame:ns_frame display:YES animate:NO]; |
| 662 |
| 663 // Setting the frame will call OnWidgetBoundsChanged(), which could result in |
| 664 // a call to EndMoveLoop(). |
| 665 if (!window_move_loop_) |
| 666 return Widget::MOVE_LOOP_SUCCESSFUL; |
| 667 |
| 668 // Make sure WindowServer has caught up with moving the window, this is |
| 669 // required in order to send the MouseDown click to the intended position. |
| 670 // I was able to always replicate old window coordinates from |
| 671 // CGSGetWindowBounds() on El Capitan. |
| 672 // DetachToBrowserTabDragControllerTest.MacDetachesAndReattachesSecondTab will |
| 673 // fail without the following NSRunLoop pass. |
| 674 [[NSRunLoop currentRunLoop] |
| 675 runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]]; |
| 676 DCHECK(NSEqualRects(ns_frame, gfx::ScreenRectToNSRect( |
| 677 native_widget_mac()->WindowServerFrame()))); |
| 678 |
| 679 return window_move_loop_->Run(); |
| 680 |
| 681 // |this| may be destroyed during the RunLoop, causing it to exit early. |
| 682 // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by |
| 683 // calling EndMoveLoop(). So window_move_loop_ will always be null before the |
| 684 // function returns. But don't DCHECK since |this| might not be valid. |
| 685 } |
| 686 |
| 687 void BridgedNativeWidget::EndMoveLoop() { |
| 688 DCHECK(window_move_loop_); |
| 689 window_move_loop_->End(); |
| 690 window_move_loop_.reset(); |
| 691 } |
| 692 |
| 693 bool BridgedNativeWidget::IsRunMoveLoopActive() const { |
| 694 return window_move_loop_.get(); |
| 695 } |
| 696 |
| 618 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, | 697 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, |
| 619 void* value) { | 698 void* value) { |
| 620 NSString* key = [NSString stringWithUTF8String:name]; | 699 NSString* key = [NSString stringWithUTF8String:name]; |
| 621 if (value) { | 700 if (value) { |
| 622 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] | 701 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] |
| 623 forKey:key]; | 702 forKey:key]; |
| 624 } else { | 703 } else { |
| 625 [GetWindowProperties() removeObjectForKey:key]; | 704 [GetWindowProperties() removeObjectForKey:key]; |
| 626 } | 705 } |
| 627 } | 706 } |
| 628 | 707 |
| 629 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { | 708 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { |
| 630 NSString* key = [NSString stringWithUTF8String:name]; | 709 NSString* key = [NSString stringWithUTF8String:name]; |
| 631 return [[GetWindowProperties() objectForKey:key] pointerValue]; | 710 return [[GetWindowProperties() objectForKey:key] pointerValue]; |
| 632 } | 711 } |
| 633 | 712 |
| 634 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { | 713 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { |
| 635 [window_delegate_ setCursor:cursor]; | 714 [window_delegate_ setCursor:cursor]; |
| 636 } | 715 } |
| 637 | 716 |
| 638 void BridgedNativeWidget::OnWindowWillClose() { | 717 void BridgedNativeWidget::OnWindowWillClose() { |
| 718 DCHECK(!drag_run_loop_); |
| 639 if (parent_) { | 719 if (parent_) { |
| 640 parent_->RemoveChildWindow(this); | 720 parent_->RemoveChildWindow(this); |
| 641 parent_ = nullptr; | 721 parent_ = nullptr; |
| 642 } | 722 } |
| 643 [window_ setDelegate:nil]; | 723 [window_ setDelegate:nil]; |
| 644 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; | 724 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
| 645 native_widget_mac_->OnWindowWillClose(); | 725 native_widget_mac_->OnWindowWillClose(); |
| 646 } | 726 } |
| 647 | 727 |
| 648 void BridgedNativeWidget::OnFullscreenTransitionStart( | 728 void BridgedNativeWidget::OnFullscreenTransitionStart( |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 | 806 |
| 727 // 10.9 is unable to generate a window shadow from the composited CALayer, so | 807 // 10.9 is unable to generate a window shadow from the composited CALayer, so |
| 728 // use Quartz. | 808 // use Quartz. |
| 729 // We don't update the window mask during a live resize, instead it is done | 809 // We don't update the window mask during a live resize, instead it is done |
| 730 // after the resize is completed in viewDidEndLiveResize: in | 810 // after the resize is completed in viewDidEndLiveResize: in |
| 731 // BridgedContentView. | 811 // BridgedContentView. |
| 732 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) | 812 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) |
| 733 [bridged_view_ updateWindowMask]; | 813 [bridged_view_ updateWindowMask]; |
| 734 } | 814 } |
| 735 | 815 |
| 816 void BridgedNativeWidget::OnPositionChanged() { |
| 817 native_widget_mac_->GetWidget()->OnNativeWidgetMove(); |
| 818 } |
| 819 |
| 736 void BridgedNativeWidget::OnVisibilityChanged() { | 820 void BridgedNativeWidget::OnVisibilityChanged() { |
| 737 OnVisibilityChangedTo([window_ isVisible]); | 821 OnVisibilityChangedTo([window_ isVisible]); |
| 738 } | 822 } |
| 739 | 823 |
| 740 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { | 824 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
| 741 if (window_visible_ == new_visibility) | 825 if (window_visible_ == new_visibility) |
| 742 return; | 826 return; |
| 743 | 827 |
| 744 window_visible_ = new_visibility; | 828 window_visible_ = new_visibility; |
| 745 | 829 |
| (...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1299 void BridgedNativeWidget::SetDraggable(bool draggable) { | 1383 void BridgedNativeWidget::SetDraggable(bool draggable) { |
| 1300 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1384 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
| 1301 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1385 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
| 1302 // changes. Previously we tried adding an NSView and removing it, but for some | 1386 // 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. | 1387 // reason it required reposting the mouse-down event, and didn't always work. |
| 1304 // Calling the below seems to be an effective solution. | 1388 // Calling the below seems to be an effective solution. |
| 1305 [window_ setMovableByWindowBackground:NO]; | 1389 [window_ setMovableByWindowBackground:NO]; |
| 1306 [window_ setMovableByWindowBackground:YES]; | 1390 [window_ setMovableByWindowBackground:YES]; |
| 1307 } | 1391 } |
| 1308 | 1392 |
| 1393 // static |
| 1394 void BridgedNativeWidget::IgnoreNextMouseDownForDraggableRegions() { |
| 1395 g_ignore_next_mouse_down_for_draggable_regions = true; |
| 1396 } |
| 1397 |
| 1309 } // namespace views | 1398 } // namespace views |
| OLD | NEW |