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

Side by Side 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 unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698