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

Unified Diff: ui/views/cocoa/bridged_native_widget.mm

Issue 2448173002: Fix processing of mouse events on MacViews.
Patch Set: Fix review issues. Created 4 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/test/event_generator_delegate_mac.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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()) {
+ 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:
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.h ('k') | ui/views/test/event_generator_delegate_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698