Chromium Code Reviews| 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 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 869 // window status. | 886 // window status. |
| 870 [bridged_view_ updateFullKeyboardAccess]; | 887 [bridged_view_ updateFullKeyboardAccess]; |
| 871 widget->GetFocusManager()->RestoreFocusedView(); | 888 widget->GetFocusManager()->RestoreFocusedView(); |
| 872 } else { | 889 } else { |
| 873 widget->OnNativeBlur(); | 890 widget->OnNativeBlur(); |
| 874 widget->GetFocusManager()->StoreFocusedView(true); | 891 widget->GetFocusManager()->StoreFocusedView(true); |
| 875 } | 892 } |
| 876 } | 893 } |
| 877 } | 894 } |
| 878 | 895 |
| 879 bool BridgedNativeWidget::ShouldRepostPendingLeftMouseDown( | 896 bool BridgedNativeWidget::ShouldDragWindow(NSEvent* event) { |
| 880 NSPoint location_in_window) { | 897 if (!bridged_view_ || [event type] != NSLeftMouseDown) |
| 881 if (!bridged_view_) | |
| 882 return false; | 898 return false; |
| 883 | 899 |
| 884 if ([bridged_view_ mouseDownCanMoveWindow]) { | 900 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_)) | 901 if (IsPointInResizeArea(location_in_window, window_)) |
| 892 return false; | 902 return false; |
| 893 | 903 |
| 894 gfx::Point point(location_in_window.x, | 904 gfx::Point point(location_in_window.x, |
| 895 NSHeight([window_ frame]) - location_in_window.y); | 905 NSHeight([window_ frame]) - location_in_window.y); |
| 896 bool should_move_window = | 906 |
| 897 native_widget_mac()->GetWidget()->GetNonClientComponent(point) == | 907 if (native_widget_mac()->GetWidget()->GetNonClientComponent(point) != |
| 898 HTCAPTION; | 908 HTCAPTION) { |
|
tapted
2016/11/08 05:03:16
nit: no curlies
karandeepb
2016/11/09 04:44:19
Done.
| |
| 909 return false; | |
| 910 } | |
| 899 | 911 |
| 900 // Check that the point is not obscured by non-content NSViews. | 912 // Check that the point is not obscured by non-content NSViews. |
| 901 for (NSView* subview : [[bridged_view_ superview] subviews]) { | 913 for (NSView* subview : [[bridged_view_ superview] subviews]) { |
| 902 if (subview == bridged_view_.get()) | 914 if (subview == bridged_view_.get()) |
| 903 continue; | 915 continue; |
| 904 | 916 |
| 905 if (![subview mouseDownCanMoveWindow] && | 917 if (![subview mouseDownCanMoveWindow] && |
| 906 NSPointInRect(location_in_window, [subview frame])) { | 918 NSPointInRect(location_in_window, [subview frame])) { |
|
tapted
2016/11/08 05:03:16
nit: no curlies
karandeepb
2016/11/09 04:44:20
Done.
| |
| 907 should_move_window = false; | 919 return false; |
| 908 break; | |
| 909 } | 920 } |
| 910 } | 921 } |
| 911 | 922 |
| 912 if (!should_move_window) | 923 return true; |
| 924 } | |
| 925 | |
| 926 bool BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(NSEvent* event) { | |
| 927 DCHECK(BridgedNativeWidget::ShouldUseDragEventMonitor()); | |
| 928 DCHECK_EQ(NSLeftMouseDown, [event type]); | |
| 929 | |
| 930 if (!bridged_view_) | |
| 931 return false; | |
| 932 | |
| 933 if ([bridged_view_ mouseDownCanMoveWindow]) { | |
| 934 // This is a re-post, the movement has already started, so we can make the | |
| 935 // window non-draggable again. | |
| 936 SetDraggable(false); | |
| 937 return false; | |
| 938 } | |
| 939 | |
| 940 if (!ShouldDragWindow(event)) | |
| 913 return false; | 941 return false; |
| 914 | 942 |
| 915 // Make the window draggable, then return true to repost the event. | 943 // Make the window draggable, then return true to repost the event. |
| 916 SetDraggable(true); | 944 SetDraggable(true); |
| 917 return true; | 945 return true; |
| 918 } | 946 } |
| 919 | 947 |
| 920 void BridgedNativeWidget::OnSizeConstraintsChanged() { | 948 void BridgedNativeWidget::OnSizeConstraintsChanged() { |
| 921 // Don't modify the size constraints or fullscreen collection behavior while | 949 // Don't modify the size constraints or fullscreen collection behavior while |
| 922 // in fullscreen or during a transition. OnFullscreenTransitionComplete will | 950 // in fullscreen or during a transition. OnFullscreenTransitionComplete will |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1368 window_, &kWindowPropertiesKey); | 1396 window_, &kWindowPropertiesKey); |
| 1369 if (!properties) { | 1397 if (!properties) { |
| 1370 properties = [NSMutableDictionary dictionary]; | 1398 properties = [NSMutableDictionary dictionary]; |
| 1371 objc_setAssociatedObject(window_, &kWindowPropertiesKey, | 1399 objc_setAssociatedObject(window_, &kWindowPropertiesKey, |
| 1372 properties, OBJC_ASSOCIATION_RETAIN); | 1400 properties, OBJC_ASSOCIATION_RETAIN); |
| 1373 } | 1401 } |
| 1374 return properties; | 1402 return properties; |
| 1375 } | 1403 } |
| 1376 | 1404 |
| 1377 void BridgedNativeWidget::SetDraggable(bool draggable) { | 1405 void BridgedNativeWidget::SetDraggable(bool draggable) { |
| 1406 DCHECK(BridgedNativeWidget::ShouldUseDragEventMonitor()); | |
| 1407 | |
| 1378 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1408 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
| 1379 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1409 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
| 1380 // changes. Previously we tried adding an NSView and removing it, but for some | 1410 // 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. | 1411 // reason it required reposting the mouse-down event, and didn't always work. |
| 1382 // Calling the below seems to be an effective solution. | 1412 // Calling the below seems to be an effective solution. |
| 1383 [window_ setMovableByWindowBackground:NO]; | 1413 [window_ setMovableByWindowBackground:NO]; |
| 1384 [window_ setMovableByWindowBackground:YES]; | 1414 [window_ setMovableByWindowBackground:YES]; |
| 1385 } | 1415 } |
| 1386 | 1416 |
| 1387 } // namespace views | 1417 } // namespace views |
| OLD | NEW |