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

Side by Side Diff: ui/views/cocoa/bridged_native_widget.mm

Issue 1877043003: [EXPERIMENT] MacViews: Implement Tab Dragging Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: git cl format 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
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/cocoa/cocoa_window_move_loop.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 17 matching lines...) Expand all
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/cocoa/cocoa_window_move_loop.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698