From e27905c7654e119464ba149f1643cd2770575159 Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Thu, 23 Feb 2023 16:05:30 -0800 Subject: [PATCH] fix: allow contextmenu event in draggable regions (#37386) --- filenames.gni | 2 +- shell/browser/api/electron_api_web_contents.h | 10 ++++- .../ui/cocoa/delayed_native_view_host.cc | 21 ----------- .../ui/cocoa/delayed_native_view_host.h | 1 + .../ui/cocoa/delayed_native_view_host.mm | 37 +++++++++++++++++++ .../electron_inspectable_web_contents_view.h | 2 + .../electron_inspectable_web_contents_view.mm | 23 ++++++++++++ 7 files changed, 73 insertions(+), 23 deletions(-) delete mode 100644 shell/browser/ui/cocoa/delayed_native_view_host.cc create mode 100644 shell/browser/ui/cocoa/delayed_native_view_host.mm diff --git a/filenames.gni b/filenames.gni index bb080c4722..b6c66b5a64 100644 --- a/filenames.gni +++ b/filenames.gni @@ -153,7 +153,7 @@ filenames = { "shell/browser/notifications/mac/notification_presenter_mac.mm", "shell/browser/relauncher_mac.cc", "shell/browser/ui/certificate_trust_mac.mm", - "shell/browser/ui/cocoa/delayed_native_view_host.cc", + "shell/browser/ui/cocoa/delayed_native_view_host.mm", "shell/browser/ui/cocoa/delayed_native_view_host.h", "shell/browser/ui/cocoa/electron_bundle_mover.h", "shell/browser/ui/cocoa/electron_bundle_mover.mm", diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index a14bd8b096..763f22123a 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -442,7 +442,13 @@ class WebContents : public ExclusiveAccessContext, // content::RenderWidgetHost::InputEventObserver: void OnInputEvent(const blink::WebInputEvent& event) override; - SkRegion* draggable_region() { return draggable_region_.get(); } + SkRegion* draggable_region() { + return force_non_draggable_ ? nullptr : draggable_region_.get(); + } + + void SetForceNonDraggable(bool force_non_draggable) { + force_non_draggable_ = force_non_draggable; + } // disable copy WebContents(const WebContents&) = delete; @@ -826,6 +832,8 @@ class WebContents : public ExclusiveAccessContext, std::unique_ptr draggable_region_; + bool force_non_draggable_ = false; + base::WeakPtrFactory weak_factory_{this}; }; diff --git a/shell/browser/ui/cocoa/delayed_native_view_host.cc b/shell/browser/ui/cocoa/delayed_native_view_host.cc deleted file mode 100644 index 5efe09686c..0000000000 --- a/shell/browser/ui/cocoa/delayed_native_view_host.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2018 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "shell/browser/ui/cocoa/delayed_native_view_host.h" - -namespace electron { - -DelayedNativeViewHost::DelayedNativeViewHost(gfx::NativeView native_view) - : native_view_(native_view) {} - -DelayedNativeViewHost::~DelayedNativeViewHost() = default; - -void DelayedNativeViewHost::ViewHierarchyChanged( - const views::ViewHierarchyChangedDetails& details) { - NativeViewHost::ViewHierarchyChanged(details); - if (details.is_add && GetWidget()) - Attach(native_view_); -} - -} // namespace electron diff --git a/shell/browser/ui/cocoa/delayed_native_view_host.h b/shell/browser/ui/cocoa/delayed_native_view_host.h index e7020dba60..eb02826c2b 100644 --- a/shell/browser/ui/cocoa/delayed_native_view_host.h +++ b/shell/browser/ui/cocoa/delayed_native_view_host.h @@ -23,6 +23,7 @@ class DelayedNativeViewHost : public views::NativeViewHost { // views::View: void ViewHierarchyChanged( const views::ViewHierarchyChangedDetails& details) override; + bool OnMousePressed(const ui::MouseEvent& event) override; private: gfx::NativeView native_view_; diff --git a/shell/browser/ui/cocoa/delayed_native_view_host.mm b/shell/browser/ui/cocoa/delayed_native_view_host.mm new file mode 100644 index 0000000000..98fc995e30 --- /dev/null +++ b/shell/browser/ui/cocoa/delayed_native_view_host.mm @@ -0,0 +1,37 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/ui/cocoa/delayed_native_view_host.h" +#include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h" + +namespace electron { + +DelayedNativeViewHost::DelayedNativeViewHost(gfx::NativeView native_view) + : native_view_(native_view) {} + +DelayedNativeViewHost::~DelayedNativeViewHost() = default; + +void DelayedNativeViewHost::ViewHierarchyChanged( + const views::ViewHierarchyChangedDetails& details) { + NativeViewHost::ViewHierarchyChanged(details); + if (details.is_add && GetWidget()) + Attach(native_view_); +} + +bool DelayedNativeViewHost::OnMousePressed(const ui::MouseEvent& ui_event) { + // NativeViewHost::OnMousePressed normally isn't called, but + // NativeWidgetMacNSWindow specifically carves out an event here for + // right-mouse-button clicks. We want to forward them to the web content, so + // handle them here. + // See: + // https://source.chromium.org/chromium/chromium/src/+/main:components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm;l=415-421;drc=a5af91924bafb85426e091c6035801990a6dc697 + ElectronInspectableWebContentsView* inspectable_web_contents_view = + (ElectronInspectableWebContentsView*)native_view_.GetNativeNSView(); + [inspectable_web_contents_view + redispatchContextMenuEvent:ui_event.native_event()]; + + return true; +} + +} // namespace electron diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h index a27cb9dd62..60f7502358 100644 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h +++ b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h @@ -46,6 +46,8 @@ using electron::InspectableWebContentsViewMac; (const DevToolsContentsResizingStrategy&)strategy; - (void)setTitle:(NSString*)title; +- (void)redispatchContextMenuEvent:(NSEvent*)theEvent; + @end #endif // ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_INSPECTABLE_WEB_CONTENTS_VIEW_H_ diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm index bceea3a147..1790ed8887 100644 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm +++ b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm @@ -5,10 +5,12 @@ #include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h" #include "content/public/browser/render_widget_host_view.h" +#include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/ui/cocoa/event_dispatching_window.h" #include "shell/browser/ui/inspectable_web_contents.h" #include "shell/browser/ui/inspectable_web_contents_view_delegate.h" #include "shell/browser/ui/inspectable_web_contents_view_mac.h" +#include "ui/base/cocoa/base_view.h" #include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h" @implementation ElectronInspectableWebContentsView @@ -273,6 +275,27 @@ [self notifyDevToolsFocused]; } +- (void)redispatchContextMenuEvent:(NSEvent*)event { + DCHECK(event.type == NSEventTypeRightMouseDown || + (event.type == NSEventTypeLeftMouseDown && + (event.modifierFlags & NSEventModifierFlagControl))); + content::WebContents* contents = + inspectableWebContentsView_->inspectable_web_contents()->GetWebContents(); + electron::api::WebContents* api_contents = + electron::api::WebContents::From(contents); + if (api_contents) { + // Temporarily pretend that the WebContents is fully non-draggable while we + // re-send the mouse event. This allows the re-dispatched event to "land" + // on the WebContents, instead of "falling through" back to the window. + api_contents->SetForceNonDraggable(true); + BaseView* contentsView = (BaseView*)contents->GetRenderWidgetHostView() + ->GetNativeView() + .GetNativeNSView(); + [contentsView mouseEvent:event]; + api_contents->SetForceNonDraggable(false); + } +} + #pragma mark - NSWindowDelegate - (void)windowWillClose:(NSNotification*)notification {