feat: support system-context-menu on Linux (#46399)

feat: support system-context-menu on Linux

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
trop[bot] 2025-04-02 14:45:28 -04:00 committed by GitHub
parent a0ac690881
commit 3acd5774da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 46 additions and 7 deletions

View file

@ -342,12 +342,12 @@ Emitted when the window has closed a sheet.
Emitted when the native new tab button is clicked.
#### Event: 'system-context-menu' _Windows_
#### Event: 'system-context-menu' _Windows_ _Linux_
Returns:
* `event` Event
* `point` [Point](structures/point.md) - The screen coordinates the context menu was triggered at
* `point` [Point](structures/point.md) - The screen coordinates where the context menu was triggered.
Emitted when the system context menu is triggered on the window, this is
normally only triggered when the user right clicks on the non-client area
@ -356,6 +356,8 @@ as `-webkit-app-region: drag` in a frameless window.
Calling `event.preventDefault()` will prevent the menu from being displayed.
To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows).
### Static Methods
The `BaseWindow` class has the following static methods:

View file

@ -421,12 +421,12 @@ Emitted when the window has closed a sheet.
Emitted when the native new tab button is clicked.
#### Event: 'system-context-menu' _Windows_
#### Event: 'system-context-menu' _Windows_ _Linux_
Returns:
* `event` Event
* `point` [Point](structures/point.md) - The screen coordinates the context menu was triggered at
* `point` [Point](structures/point.md) - The screen coordinates where the context menu was triggered.
Emitted when the system context menu is triggered on the window, this is
normally only triggered when the user right clicks on the non-client area
@ -435,6 +435,8 @@ as `-webkit-app-region: drag` in a frameless window.
Calling `event.preventDefault()` will prevent the menu from being displayed.
To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows).
### Static Methods
The `BrowserWindow` class has the following static methods:

View file

@ -17,6 +17,9 @@
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/views/client_frame_view_linux.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/window_delegate.h"
#include "ui/base/hit_test.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/linux/linux_ui.h"
@ -262,13 +265,45 @@ void ElectronDesktopWindowTreeHostLinux::DispatchEvent(ui::Event* event) {
is_mousedown &&
(mouse_event->IsRightMouseButton() ||
(mouse_event->IsLeftMouseButton() && mouse_event->IsControlDown()));
if (is_system_menu_trigger) {
electron::api::WebContents::SetDisableDraggableRegions(true);
if (!is_system_menu_trigger) {
views::DesktopWindowTreeHostLinux::DispatchEvent(event);
electron::api::WebContents::SetDisableDraggableRegions(false);
return;
}
// Determine the non-client area and dispatch 'system-context-menu'.
if (GetContentWindow() && GetContentWindow()->delegate()) {
ui::LocatedEvent* located_event = event->AsLocatedEvent();
gfx::PointF location = located_event->location_f();
gfx::PointF location_in_dip =
GetRootTransform().InverseMapPoint(location).value_or(location);
int hit_test_code = GetContentWindow()->delegate()->GetNonClientComponent(
gfx::ToRoundedPoint(location_in_dip));
if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE) {
bool prevent_default = false;
native_window_view_->NotifyWindowSystemContextMenu(
located_event->x(), located_event->y(), &prevent_default);
// If |prevent_default| is true, then the user might want to show a
// custom menu - proceed propagation and emit context-menu in the
// renderer. Otherwise, show the native system window controls menu.
if (prevent_default) {
electron::api::WebContents::SetDisableDraggableRegions(true);
views::DesktopWindowTreeHostLinux::DispatchEvent(event);
electron::api::WebContents::SetDisableDraggableRegions(false);
} else {
if (ui::OzonePlatform::GetInstance()
->GetPlatformRuntimeProperties()
.supports_server_window_menus) {
views::DesktopWindowTreeHostLinux::ShowWindowControlsMenu(
display::Screen::GetScreen()->GetCursorScreenPoint());
}
}
return;
}
}
}
views::DesktopWindowTreeHostLinux::DispatchEvent(event);
}