Skip to content

Commit

Permalink
fix: Do not activate app when calling focus on inactive panel window
Browse files Browse the repository at this point in the history
  • Loading branch information
felixrieseberg committed Nov 3, 2023
1 parent f501dab commit 8da57e2
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
24 changes: 23 additions & 1 deletion shell/browser/native_window_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ bool IsFramelessWindow(NSView* view) {
return window && !window->has_frame();
}

bool IsPanel(NSWindow* window) {
return [window level] == NSFloatingWindowLevel;
}

IMP original_set_frame_size = nullptr;
IMP original_view_did_move_to_superview = nullptr;

Expand Down Expand Up @@ -469,7 +473,25 @@ void ReorderChildWindowAbove(NSWindow* child_window, NSWindow* other_window) {
return;

if (focus) {
[[NSApplication sharedApplication] activateIgnoringOtherApps:NO];
// If we're a panel window, we do not want to activate the app,
// which enables Electron-apps to build Spotlight-like experiences.
//
// On macOS < Sonoma, "activateIgnoringOtherApps:NO" would not
// activate apps if focusing a window that is inActive. That
// changed with macOS Sonoma.
//
// 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] activateIgnoringOtherApps:NO];
}
} else {
[[NSApplication sharedApplication] activateIgnoringOtherApps:NO];
}

[window_ makeKeyAndOrderFront:nil];
} else {
[window_ orderOut:nil];
Expand Down
34 changes: 34 additions & 0 deletions spec/api-browser-window-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,40 @@ describe('BrowserWindow module', () => {
await isClosed3;
}
});

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();
w.destroy();

// We first need to resign app focus for this test to work
const isInactive = once(app, 'did-resign-active');
childProcess.execSync('osascript -e \'tell application "Finder" to activate\'');
await isInactive;

// Create new window
w = new BrowserWindow({
type: 'panel',
height: 200,
width: 200,
center: true,
show: false
});

const isShow = once(w, 'show');
const isFocus = once(w, 'focus');

w.showInactive();
w.focus();

await isShow;
await isFocus;

const getActiveAppOsa = 'tell application "System Events" to get the name of the first process whose frontmost is true';
const activeApp = childProcess.execSync(`osascript -e '${getActiveAppOsa}'`).toString().trim();

expect(activeApp).to.equal('Finder');
});
});

// TODO(RaisinTen): Make this work on Windows too.
Expand Down

0 comments on commit 8da57e2

Please sign in to comment.