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

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

Issue 2475173002: MacViews: Fix window dragging on Sierra. (Closed)
Patch Set: Rebase. Update comment. #include=>#import. Created 4 years, 1 month 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 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 if (can_resize_x && can_resize_y && 162 if (can_resize_x && can_resize_y &&
163 (point.x < kResizeAreaCornerSize || 163 (point.x < kResizeAreaCornerSize ||
164 point.x >= window_size.width - kResizeAreaCornerSize) && 164 point.x >= window_size.width - kResizeAreaCornerSize) &&
165 (point.y < kResizeAreaCornerSize || 165 (point.y < kResizeAreaCornerSize ||
166 point.y >= window_size.height - kResizeAreaCornerSize)) 166 point.y >= window_size.height - kResizeAreaCornerSize))
167 return true; 167 return true;
168 168
169 return false; 169 return false;
170 } 170 }
171 171
172 // Routes the |ns_event| to the corresponding BridgedNativeWidget and queries
173 // whether the event should be reposted.
172 BOOL WindowWantsMouseDownReposted(NSEvent* ns_event) { 174 BOOL WindowWantsMouseDownReposted(NSEvent* ns_event) {
173 id delegate = [[ns_event window] delegate]; 175 DCHECK(views::BridgedNativeWidget::ShouldUseDragEventMonitor());
174 return 176
175 [delegate 177 views::BridgedNativeWidget* bridge =
176 respondsToSelector:@selector(shouldRepostPendingLeftMouseDown:)] && 178 views::NativeWidgetMac::GetBridgeForNativeWindow([ns_event window]);
177 [delegate shouldRepostPendingLeftMouseDown:[ns_event locationInWindow]]; 179 return bridge && bridge->ShouldRepostPendingLeftMouseDown(ns_event);
178 } 180 }
179 181
180 // Check if a mouse-down event should drag the window. If so, repost the event. 182 // Check if a mouse-down event should drag the window. If so, repost the event.
181 NSEvent* RepostEventIfHandledByWindow(NSEvent* ns_event) { 183 NSEvent* RepostEventIfHandledByWindow(NSEvent* ns_event) {
184 DCHECK(views::BridgedNativeWidget::ShouldUseDragEventMonitor());
185
182 enum RepostState { 186 enum RepostState {
183 // Nothing reposted: hit-test new mouse-downs to see if they need to be 187 // Nothing reposted: hit-test new mouse-downs to see if they need to be
184 // ignored and reposted after changing draggability. 188 // ignored and reposted after changing draggability.
185 NONE, 189 NONE,
186 // Expecting the next event to be the reposted event: let it go through. 190 // Expecting the next event to be the reposted event: let it go through.
187 EXPECTING_REPOST, 191 EXPECTING_REPOST,
188 // If, while reposting, another mousedown was received: when the reposted 192 // If, while reposting, another mousedown was received: when the reposted
189 // event is seen, ignore it. 193 // event is seen, ignore it.
190 REPOST_CANCELLED, 194 REPOST_CANCELLED,
191 }; 195 };
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 250
247 // Support window caption/draggable regions. 251 // Support window caption/draggable regions.
248 // In AppKit, non-client regions are set by overriding 252 // In AppKit, non-client regions are set by overriding
249 // -[NSView mouseDownCanMoveWindow]. NSApplication caches this area as views are 253 // -[NSView mouseDownCanMoveWindow]. NSApplication caches this area as views are
250 // installed and performs window moving when mouse-downs land in the area. 254 // installed and performs window moving when mouse-downs land in the area.
251 // In Views, non-client regions are determined via hit-tests when the event 255 // In Views, non-client regions are determined via hit-tests when the event
252 // occurs. 256 // occurs.
253 // To bridge the two models, we monitor mouse-downs with 257 // To bridge the two models, we monitor mouse-downs with
254 // +[NSEvent addLocalMonitorForEventsMatchingMask:handler:]. This receives 258 // +[NSEvent addLocalMonitorForEventsMatchingMask:handler:]. This receives
255 // events after window dragging is handled, so for mouse-downs that land on a 259 // events after window dragging is handled, so for mouse-downs that land on a
256 // draggable point, we cancel the event and repost it at the CGSessionEventTap 260 // draggable point, we cancel the event, make the window draggable and repost it
257 // level so that window dragging will be handled again. 261 // at the CGSessionEventTap level so that window dragging will be handled again.
262 // On Mac OS > 10.10, we don't use an event monitor. Instead, we use [NSWindow
263 // performWindowDragWithEvent:]. See [NativeWidgetMacNSWindow sendEvent:].
258 void SetupDragEventMonitor() { 264 void SetupDragEventMonitor() {
265 DCHECK(views::BridgedNativeWidget::ShouldUseDragEventMonitor());
259 static id monitor = nil; 266 static id monitor = nil;
260 if (monitor) 267 if (monitor)
261 return; 268 return;
262 269
263 monitor = [NSEvent 270 monitor = [NSEvent
264 addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask 271 addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask
265 handler:^NSEvent*(NSEvent* ns_event) { 272 handler:^NSEvent*(NSEvent* ns_event) {
266 return RepostEventIfHandledByWindow(ns_event); 273 return RepostEventIfHandledByWindow(ns_event);
267 }]; 274 }];
268 } 275 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 // static 338 // static
332 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( 339 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize(
333 NSWindow* window, 340 NSWindow* window,
334 const gfx::Size& content_size) { 341 const gfx::Size& content_size) {
335 NSRect content_rect = 342 NSRect content_rect =
336 NSMakeRect(0, 0, content_size.width(), content_size.height()); 343 NSMakeRect(0, 0, content_size.width(), content_size.height());
337 NSRect frame_rect = [window frameRectForContentRect:content_rect]; 344 NSRect frame_rect = [window frameRectForContentRect:content_rect];
338 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); 345 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
339 } 346 }
340 347
348 // static
349 // TODO(karandeepb): Remove usage of drag event monitor once we stop supporting
350 // Mac OS 10.10.
351 bool BridgedNativeWidget::ShouldUseDragEventMonitor() {
352 return ![NSWindow
353 instancesRespondToSelector:@selector(performWindowDragWithEvent:)];
354 }
355
341 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent) 356 BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
342 : native_widget_mac_(parent), 357 : native_widget_mac_(parent),
343 focus_manager_(nullptr), 358 focus_manager_(nullptr),
344 widget_type_(Widget::InitParams::TYPE_WINDOW), // Updated in Init(). 359 widget_type_(Widget::InitParams::TYPE_WINDOW), // Updated in Init().
345 parent_(nullptr), 360 parent_(nullptr),
346 target_fullscreen_state_(false), 361 target_fullscreen_state_(false),
347 in_fullscreen_transition_(false), 362 in_fullscreen_transition_(false),
348 window_visible_(false), 363 window_visible_(false),
349 wants_to_be_visible_(false) { 364 wants_to_be_visible_(false) {
350 SetupDragEventMonitor(); 365 if (BridgedNativeWidget::ShouldUseDragEventMonitor())
366 SetupDragEventMonitor();
367
351 DCHECK(parent); 368 DCHECK(parent);
352 window_delegate_.reset( 369 window_delegate_.reset(
353 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); 370 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
354 } 371 }
355 372
356 BridgedNativeWidget::~BridgedNativeWidget() { 373 BridgedNativeWidget::~BridgedNativeWidget() {
357 // The delegate should be cleared already. Note this enforces the precondition 374 // The delegate should be cleared already. Note this enforces the precondition
358 // that -[NSWindow close] is invoked on the hosted window before the 375 // that -[NSWindow close] is invoked on the hosted window before the
359 // destructor is called. 376 // destructor is called.
360 DCHECK(![window_ delegate]); 377 DCHECK(![window_ delegate]);
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 571
555 if (native_widget_mac_->IsWindowModalSheet()) { 572 if (native_widget_mac_->IsWindowModalSheet()) {
556 ShowAsModalSheet(); 573 ShowAsModalSheet();
557 return; 574 return;
558 } 575 }
559 576
560 // Non-modal windows are not animated. Hence opaque non-modal windows can 577 // Non-modal windows are not animated. Hence opaque non-modal windows can
561 // appear with a "flash" if they are made visible before the frame from the 578 // appear with a "flash" if they are made visible before the frame from the
562 // compositor arrives. To get around this, set the alpha value of the window 579 // compositor arrives. To get around this, set the alpha value of the window
563 // to 0, till we receive the correct frame from the compositor. Also, ignore 580 // to 0, till we receive the correct frame from the compositor. Also, ignore
564 // mouse clicks till then. 581 // mouse clicks till then. Also check for an active task runner on the
582 // WindowResizeHelperMac instance to ensure visibility is only suppressed when
583 // there is an active GPU process.
565 // TODO(karandeepb): Investigate whether similar technique is needed for other 584 // TODO(karandeepb): Investigate whether similar technique is needed for other
566 // dialog types. 585 // dialog types.
567 if (layer() && [window_ isOpaque] && !window_visible_ && 586 if (layer() && [window_ isOpaque] && !window_visible_ &&
568 !native_widget_mac_->GetWidget()->IsModal()) { 587 !native_widget_mac_->GetWidget()->IsModal() &&
588 ui::WindowResizeHelperMac::Get()->task_runner()) {
569 initial_visibility_suppressed_ = true; 589 initial_visibility_suppressed_ = true;
570 [window_ setAlphaValue:0.0]; 590 [window_ setAlphaValue:0.0];
571 [window_ setIgnoresMouseEvents:YES]; 591 [window_ setIgnoresMouseEvents:YES];
572 } 592 }
573 593
574 if (new_state == SHOW_AND_ACTIVATE_WINDOW) { 594 if (new_state == SHOW_AND_ACTIVATE_WINDOW) {
575 [window_ makeKeyAndOrderFront:nil]; 595 [window_ makeKeyAndOrderFront:nil];
576 [NSApp activateIgnoringOtherApps:YES]; 596 [NSApp activateIgnoringOtherApps:YES];
577 } else { 597 } else {
578 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a 598 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 // window status. 889 // window status.
870 [bridged_view_ updateFullKeyboardAccess]; 890 [bridged_view_ updateFullKeyboardAccess];
871 widget->GetFocusManager()->RestoreFocusedView(); 891 widget->GetFocusManager()->RestoreFocusedView();
872 } else { 892 } else {
873 widget->OnNativeBlur(); 893 widget->OnNativeBlur();
874 widget->GetFocusManager()->StoreFocusedView(true); 894 widget->GetFocusManager()->StoreFocusedView(true);
875 } 895 }
876 } 896 }
877 } 897 }
878 898
879 bool BridgedNativeWidget::ShouldRepostPendingLeftMouseDown( 899 bool BridgedNativeWidget::ShouldDragWindow(NSEvent* event) {
880 NSPoint location_in_window) { 900 if (!bridged_view_ || [event type] != NSLeftMouseDown)
881 if (!bridged_view_)
882 return false; 901 return false;
883 902
884 if ([bridged_view_ mouseDownCanMoveWindow]) { 903 NSPoint location_in_window = [event locationInWindow];
885 // This is a re-post, the movement has already started, so we can make the
886 // window non-draggable again.
887 SetDraggable(false);
888 return false;
889 }
890
891 if (IsPointInResizeArea(location_in_window, window_)) 904 if (IsPointInResizeArea(location_in_window, window_))
892 return false; 905 return false;
893 906
894 gfx::Point point(location_in_window.x, 907 gfx::Point point(location_in_window.x,
895 NSHeight([window_ frame]) - location_in_window.y); 908 NSHeight([window_ frame]) - location_in_window.y);
896 bool should_move_window = 909
897 native_widget_mac()->GetWidget()->GetNonClientComponent(point) == 910 if (native_widget_mac()->GetWidget()->GetNonClientComponent(point) !=
898 HTCAPTION; 911 HTCAPTION)
912 return false;
899 913
900 // Check that the point is not obscured by non-content NSViews. 914 // Check that the point is not obscured by non-content NSViews.
901 for (NSView* subview : [[bridged_view_ superview] subviews]) { 915 for (NSView* subview : [[bridged_view_ superview] subviews]) {
902 if (subview == bridged_view_.get()) 916 if (subview == bridged_view_.get())
903 continue; 917 continue;
904 918
905 if (![subview mouseDownCanMoveWindow] && 919 if (![subview mouseDownCanMoveWindow] &&
906 NSPointInRect(location_in_window, [subview frame])) { 920 NSPointInRect(location_in_window, [subview frame]))
907 should_move_window = false; 921 return false;
908 break;
909 }
910 } 922 }
911 923
912 if (!should_move_window) 924 return true;
925 }
926
927 bool BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(NSEvent* event) {
928 DCHECK(BridgedNativeWidget::ShouldUseDragEventMonitor());
929 DCHECK_EQ(NSLeftMouseDown, [event type]);
930
931 if (!bridged_view_)
932 return false;
933
934 if ([bridged_view_ mouseDownCanMoveWindow]) {
935 // This is a re-post, the movement has already started, so we can make the
936 // window non-draggable again.
937 SetDraggable(false);
938 return false;
939 }
940
941 if (!ShouldDragWindow(event))
913 return false; 942 return false;
914 943
915 // Make the window draggable, then return true to repost the event. 944 // Make the window draggable, then return true to repost the event.
916 SetDraggable(true); 945 SetDraggable(true);
917 return true; 946 return true;
918 } 947 }
919 948
920 void BridgedNativeWidget::OnSizeConstraintsChanged() { 949 void BridgedNativeWidget::OnSizeConstraintsChanged() {
921 // Don't modify the size constraints or fullscreen collection behavior while 950 // Don't modify the size constraints or fullscreen collection behavior while
922 // in fullscreen or during a transition. OnFullscreenTransitionComplete will 951 // in fullscreen or during a transition. OnFullscreenTransitionComplete will
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 window_, &kWindowPropertiesKey); 1397 window_, &kWindowPropertiesKey);
1369 if (!properties) { 1398 if (!properties) {
1370 properties = [NSMutableDictionary dictionary]; 1399 properties = [NSMutableDictionary dictionary];
1371 objc_setAssociatedObject(window_, &kWindowPropertiesKey, 1400 objc_setAssociatedObject(window_, &kWindowPropertiesKey,
1372 properties, OBJC_ASSOCIATION_RETAIN); 1401 properties, OBJC_ASSOCIATION_RETAIN);
1373 } 1402 }
1374 return properties; 1403 return properties;
1375 } 1404 }
1376 1405
1377 void BridgedNativeWidget::SetDraggable(bool draggable) { 1406 void BridgedNativeWidget::SetDraggable(bool draggable) {
1407 DCHECK(BridgedNativeWidget::ShouldUseDragEventMonitor());
1408
1378 [bridged_view_ setMouseDownCanMoveWindow:draggable]; 1409 [bridged_view_ setMouseDownCanMoveWindow:draggable];
1379 // AppKit will not update its cache of mouseDownCanMoveWindow unless something 1410 // AppKit will not update its cache of mouseDownCanMoveWindow unless something
1380 // changes. Previously we tried adding an NSView and removing it, but for some 1411 // changes. Previously we tried adding an NSView and removing it, but for some
1381 // reason it required reposting the mouse-down event, and didn't always work. 1412 // reason it required reposting the mouse-down event, and didn't always work.
1382 // Calling the below seems to be an effective solution. 1413 // Calling the below seems to be an effective solution.
1383 [window_ setMovableByWindowBackground:NO]; 1414 [window_ setMovableByWindowBackground:NO];
1384 [window_ setMovableByWindowBackground:YES]; 1415 [window_ setMovableByWindowBackground:YES];
1385 } 1416 }
1386 1417
1387 } // namespace views 1418 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/cocoa/bridged_native_widget_interactive_uitest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698