Chromium Code Reviews| Index: ui/views/cocoa/bridged_native_widget.mm |
| diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm |
| index 8e47513350dc150013b5a19023ea9e969f42d8e1..5e1c24a31ce817e9516ae8f5118a2807b97e948f 100644 |
| --- a/ui/views/cocoa/bridged_native_widget.mm |
| +++ b/ui/views/cocoa/bridged_native_widget.mm |
| @@ -14,20 +14,22 @@ |
| #import "base/mac/sdk_forward_declarations.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" |
| +#include "ui/base/cocoa/cocoa_base_utils.h" |
| #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/base/ime/input_method.h" |
| #include "ui/base/ime/input_method_factory.h" |
| #include "ui/display/display.h" |
| #include "ui/display/screen.h" |
| +#include "ui/events/event_utils.h" |
| #include "ui/gfx/geometry/dip_util.h" |
| #import "ui/gfx/mac/coordinate_conversion.h" |
| #import "ui/gfx/mac/nswindow_frame_controls.h" |
| #import "ui/native_theme/native_theme_mac.h" |
| #import "ui/views/cocoa/bridged_content_view.h" |
| -#import "ui/views/cocoa/drag_drop_client_mac.h" |
| #import "ui/views/cocoa/cocoa_mouse_capture.h" |
| #import "ui/views/cocoa/cocoa_window_move_loop.h" |
| +#import "ui/views/cocoa/drag_drop_client_mac.h" |
| #include "ui/views/cocoa/tooltip_manager_mac.h" |
| #import "ui/views/cocoa/views_nswindow_delegate.h" |
| #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" |
| @@ -323,6 +325,28 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { |
| return count; |
| } |
| +// Convert an |event|'s mouse point to |target_view|'s content rect, with the |
| +// origin at the top left of the content area. |
| +// If -[|event| window] is nil, original point will be treated as screen |
| +// coordinates. |
| +gfx::Point GetEventLocationInView(NSEvent* event, NSView* target_view) { |
| + NSWindow* source = [event window]; |
| + NSWindow* target = [target_view window]; |
| + DCHECK(target); |
| + NSPoint point_in_window = [event locationInWindow]; |
| + if (![target isEqual:source]) { |
| + NSPoint point_in_screen = |
| + source ? ui::ConvertPointFromWindowToScreen(source, point_in_window) |
| + : point_in_window; |
| + point_in_window = |
| + ui::ConvertPointFromScreenToWindow(target, point_in_screen); |
| + } |
| + NSPoint point_in_view = |
| + [target_view convertPoint:point_in_window fromView:nil]; |
| + return gfx::Point(point_in_view.x, |
| + NSHeight([target_view frame]) - point_in_view.y); |
| +} |
| + |
| } // namespace |
| namespace views { |
| @@ -1061,17 +1085,93 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) { |
| // BridgedNativeWidget, CocoaMouseCaptureDelegate: |
| void BridgedNativeWidget::PostCapturedEvent(NSEvent* event) { |
| - [bridged_view_ processCapturedMouseEvent:event]; |
| + OnMouseEvent(event); |
| } |
| void BridgedNativeWidget::OnMouseCaptureLost() { |
| native_widget_mac_->GetWidget()->OnMouseCaptureLost(); |
| + SendStoredMouseExitedEventToWidget(); |
| } |
| NSWindow* BridgedNativeWidget::GetWindow() const { |
| return window_; |
| } |
| +void BridgedNativeWidget::OnMouseEvent(NSEvent* native_event) { |
| + pendingExitEvent_.reset(); |
| + |
| + const gfx::Point location = |
| + GetEventLocationInView(native_event, bridged_view_); |
| + views::Widget* widget = native_widget_mac_->GetWidget(); |
| + |
| + bool event_inside_widget = false; |
| + if (widget->HasHitTestMask()) { |
|
tapted
2016/10/26 00:57:00
Event handling doesn't belong in BridgedNativeWidg
snake
2016/10/26 12:44:56
BridgedNativeWidget is more appropriate place for
tapted
2016/10/27 02:39:10
What about [BridgedContentView processCapturedMous
snake
2016/10/27 10:54:22
Hm... I do not see any Capturing methods in Bridge
|
| + gfx::Path hit_test_mask; |
| + widget->GetHitTestMask(&hit_test_mask); |
| + event_inside_widget = hit_test_mask.contains(location.x(), location.y()); |
| + } else { |
| + event_inside_widget = |
| + gfx::Rect(widget->GetWindowBoundsInScreen().size()).Contains(location); |
| + } |
| + const bool should_send_entered_event = |
| + !mouse_inside_ && (event_inside_widget || HasCapture()); |
| + if (should_send_entered_event) { |
| + ui::MouseEvent entered_event(ui::ET_MOUSE_ENTERED, location, location, |
| + ui::EventTimeFromNative(native_event), |
| + ui::EF_NONE, ui::EF_NONE); |
| + widget->OnMouseEvent(&entered_event); |
| + mouse_inside_ = true; |
| + } |
| + |
| + if (!mouse_inside_) { |
| + return [bridged_view_ passMouseEventToSuperview:native_event]; |
| + } |
| + |
| + if ([native_event type] == NSScrollWheel) { |
| + ui::ScrollEvent event(native_event); |
| + event.set_location(location); |
| + widget->OnScrollEvent(&event); |
| + } else if ([native_event type] != NSMouseEntered && |
| + [native_event type] != NSMouseExited) { |
| + ui::MouseEvent event(native_event); |
| + event.set_location(location); |
| + widget->OnMouseEvent(&event); |
| + } |
| + // We could get an NSMouseExited with its location within the bounds of the |
| + // view. |
| + const bool should_send_exited_event = |
| + !HasCapture() && |
| + (!event_inside_widget || [native_event type] == NSMouseExited); |
| + // If we don't need to send the ET_MOUSE_EXITED event immediately, postpone it |
| + // until later. |
| + const bool should_create_exited_event = |
| + should_send_exited_event || !event_inside_widget; |
| + |
| + if (should_create_exited_event) { |
| + // The tracking area will send an exit event even during a drag, which isn't |
| + // how the event flow for drags should work. This stores the exit event, and |
| + // sends it when the drag completes instead. |
| + pendingExitEvent_.reset(new ui::MouseEvent( |
| + ui::ET_MOUSE_EXITED, location, location, |
| + ui::EventTimeFromNative(native_event), ui::EF_NONE, ui::EF_NONE)); |
| + } |
| + |
| + if (should_send_exited_event) { |
| + SendStoredMouseExitedEventToWidget(); |
| + } else { |
| + [bridged_view_ updateTooltipIfRequiredAt:location]; |
| + } |
| +} |
| + |
| +void BridgedNativeWidget::SendStoredMouseExitedEventToWidget() { |
| + if (pendingExitEvent_) { |
| + mouse_inside_ = false; |
| + auto exited_event = std::move(pendingExitEvent_); |
| + native_widget_mac_->GetWidget()->OnMouseEvent(exited_event.get()); |
| + [bridged_view_ hideTooltipIfRequired]; |
| + } |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // BridgedNativeWidget, FocusChangeListener: |