fix: do not activate app when showing a panel on Mac (#41750)

* fix: do not activate app when showing or focusing a panel on Mac

* restored panel activation test
This commit is contained in:
Mitchell Cohen 2024-04-12 08:27:59 -04:00 коммит произвёл GitHub
Родитель db11090e58
Коммит 05fba85aa3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 28 добавлений и 32 удалений

Просмотреть файл

@ -176,6 +176,8 @@ class NativeWindowMac : public NativeWindow,
void UpdateWindowOriginalFrame();
bool IsPanel();
// Set the attribute of NSWindow while work around a bug of zoom button.
bool HasStyleMask(NSUInteger flag) const;
void SetStyleMask(bool on, NSUInteger flag);

Просмотреть файл

@ -25,6 +25,7 @@
#include "shell/browser/browser.h"
#include "shell/browser/javascript_environment.h"
#include "shell/browser/ui/cocoa/electron_native_widget_mac.h"
#include "shell/browser/ui/cocoa/electron_ns_panel.h"
#include "shell/browser/ui/cocoa/electron_ns_window.h"
#include "shell/browser/ui/cocoa/electron_ns_window_delegate.h"
#include "shell/browser/ui/cocoa/electron_preview_item.h"
@ -117,11 +118,6 @@ struct Converter<electron::NativeWindowMac::VisualEffectState> {
namespace electron {
namespace {
bool IsPanel(NSWindow* window) {
return [window isKindOfClass:[NSPanel class]];
}
// -[NSWindow orderWindow] does not handle reordering for children
// windows. Their order is fixed to the attachment order (the last attached
// window is on the top). Therefore, work around it by re-parenting in our
@ -429,30 +425,22 @@ void NativeWindowMac::Focus(bool focus) {
if (focus) {
// If we're a panel window, we do not want to activate the app,
// which enables Electron-apps to build Spotlight-like experiences.
//
if (!IsPanel()) {
// On macOS < Sonoma, "activateIgnoringOtherApps:NO" would not
// activate apps if focusing a window that is inActive. That
// changed with macOS Sonoma, which also deprecated
// "activateIgnoringOtherApps". For the panel-specific usecase,
// we can simply replace "activateIgnoringOtherApps:NO" with
// "activate". For details on why we cannot replace all calls 1:1,
// please see
// https://github.com/electron/electron/pull/40307#issuecomment-1801976591.
// "activateIgnoringOtherApps".
//
// There's a slim chance we should have never called
// activateIgnoringOtherApps, but we tried that many years ago
// and saw weird focus bugs on other macOS versions. So, to make
// this safe, we're gating by versions.
if (@available(macOS 14.0, *)) {
if (!IsPanel(window_)) {
[[NSApplication sharedApplication] activate];
} else {
[[NSApplication sharedApplication] activateIgnoringOtherApps:NO];
}
} else {
[[NSApplication sharedApplication] activateIgnoringOtherApps:NO];
}
[window_ makeKeyAndOrderFront:nil];
} else {
[window_ orderOut:nil];
@ -480,10 +468,14 @@ void NativeWindowMac::Show() {
if (parent())
InternalSetParentWindow(parent(), true);
// This method is supposed to put focus on window, however if the app does not
// have focus then "makeKeyAndOrderFront" will only show the window.
[NSApp activateIgnoringOtherApps:YES];
// Panels receive key focus when shown but should not activate the app.
if (!IsPanel()) {
if (@available(macOS 14.0, *)) {
[[NSApplication sharedApplication] activate];
} else {
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
}
[window_ makeKeyAndOrderFront:nil];
}
@ -625,6 +617,10 @@ bool NativeWindowMac::IsMinimized() const {
return [window_ isMiniaturized];
}
bool NativeWindowMac::IsPanel() {
return [window_ isKindOfClass:[ElectronNSPanel class]];
}
bool NativeWindowMac::HandleDeferredClose() {
if (has_deferred_window_close_) {
SetHasDeferredWindowClose(false);

Просмотреть файл

@ -1246,7 +1246,6 @@ describe('BrowserWindow module', () => {
}
});
// FIXME: disabled in `disabled-tests.json`
ifit(process.platform === 'darwin')('it does not activate the app if focusing an inactive panel', async () => {
// Show to focus app, then remove existing window
w.show();
@ -1269,7 +1268,7 @@ describe('BrowserWindow module', () => {
const isShow = once(w, 'show');
const isFocus = once(w, 'focus');
w.showInactive();
w.show();
w.focus();
await isShow;

Просмотреть файл

@ -7,6 +7,5 @@
"session module ses.cookies should set cookie for standard scheme",
"webFrameMain module WebFrame.visibilityState should match window state",
"reporting api sends a report for a deprecation",
"chromium features SpeechSynthesis should emit lifecycle events",
"BrowserWindow module focus and visibility BrowserWindow.focus() it does not activate the app if focusing an inactive panel"
"chromium features SpeechSynthesis should emit lifecycle events"
]