diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md
index 5f21805d8717..d2f3a35991ef 100644
--- a/docs/api/browser-window.md
+++ b/docs/api/browser-window.md
@@ -192,6 +192,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
macOS. Default is `false`.
* `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar.
Default is `false`.
+ * `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control.
* `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`.
* `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `
` is defined in the HTML file loaded by `loadURL()`, this property will be ignored.
* `icon` ([NativeImage](native-image.md) | string) (optional) - The window icon. On Windows it is
@@ -1255,6 +1256,16 @@ Returns `boolean` - Whether the window can be manually closed by user.
On Linux always returns `true`.
+#### `win.setHiddenInMissionControl(hidden)` _macOS_
+
+* `hidden` boolean
+
+Sets whether the window will be hidden when the user toggles into mission control.
+
+#### `win.isHiddenInMissionControl()` _macOS_
+
+Returns `boolean` - Whether the window will be hidden when the user toggles into mission control.
+
#### `win.setAlwaysOnTop(flag[, level][, relativeLevel])`
* `flag` boolean
diff --git a/shell/browser/api/electron_api_base_window.cc b/shell/browser/api/electron_api_base_window.cc
index 6aa498923e94..6ecc2684d106 100644
--- a/shell/browser/api/electron_api_base_window.cc
+++ b/shell/browser/api/electron_api_base_window.cc
@@ -881,6 +881,16 @@ gfx::Point BaseWindow::GetTrafficLightPosition() const {
}
#endif
+#if BUILDFLAG(IS_MAC)
+bool BaseWindow::IsHiddenInMissionControl() {
+ return window_->IsHiddenInMissionControl();
+}
+
+void BaseWindow::SetHiddenInMissionControl(bool hidden) {
+ window_->SetHiddenInMissionControl(hidden);
+}
+#endif
+
void BaseWindow::SetTouchBar(
std::vector items) {
window_->SetTouchBar(std::move(items));
@@ -1256,6 +1266,14 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getTrafficLightPosition",
&BaseWindow::GetTrafficLightPosition)
#endif
+
+#if BUILDFLAG(IS_MAC)
+ .SetMethod("isHiddenInMissionControl",
+ &BaseWindow::IsHiddenInMissionControl)
+ .SetMethod("setHiddenInMissionControl",
+ &BaseWindow::SetHiddenInMissionControl)
+#endif
+
.SetMethod("_setTouchBarItems", &BaseWindow::SetTouchBar)
.SetMethod("_refreshTouchBarItem", &BaseWindow::RefreshTouchBarItem)
.SetMethod("_setEscapeTouchBarItem", &BaseWindow::SetEscapeTouchBarItem)
diff --git a/shell/browser/api/electron_api_base_window.h b/shell/browser/api/electron_api_base_window.h
index 5500006939b9..9552a13a5983 100644
--- a/shell/browser/api/electron_api_base_window.h
+++ b/shell/browser/api/electron_api_base_window.h
@@ -198,6 +198,11 @@ class BaseWindow : public gin_helper::TrackableObject,
gfx::Point GetTrafficLightPosition() const;
#endif
+#if BUILDFLAG(IS_MAC)
+ bool IsHiddenInMissionControl();
+ void SetHiddenInMissionControl(bool hidden);
+#endif
+
void SetTouchBar(std::vector items);
void RefreshTouchBarItem(const std::string& item_id);
void SetEscapeTouchBarItem(gin_helper::PersistentDictionary item);
diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h
index fcf1d2d6bd28..6eccbf2a9805 100644
--- a/shell/browser/native_window.h
+++ b/shell/browser/native_window.h
@@ -227,6 +227,12 @@ class NativeWindow : public base::SupportsUserData,
virtual void UpdateFrame() = 0;
#endif
+// whether windows should be ignored by mission control
+#if BUILDFLAG(IS_MAC)
+ virtual bool IsHiddenInMissionControl() = 0;
+ virtual void SetHiddenInMissionControl(bool hidden) = 0;
+#endif
+
// Touchbar API
virtual void SetTouchBar(std::vector items);
virtual void RefreshTouchBarItem(const std::string& item_id);
diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h
index 1e436cebad02..2d6722bad73b 100644
--- a/shell/browser/native_window_mac.h
+++ b/shell/browser/native_window_mac.h
@@ -103,6 +103,8 @@ class NativeWindowMac : public NativeWindow,
void SetDocumentEdited(bool edited) override;
bool IsDocumentEdited() override;
void SetIgnoreMouseEvents(bool ignore, bool forward) override;
+ bool IsHiddenInMissionControl() override;
+ void SetHiddenInMissionControl(bool hidden) override;
void SetContentProtection(bool enable) override;
void SetFocusable(bool focusable) override;
bool IsFocusable() override;
diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm
index e2252b50eb88..afd3add3ae59 100644
--- a/shell/browser/native_window_mac.mm
+++ b/shell/browser/native_window_mac.mm
@@ -209,6 +209,9 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
std::string windowType;
options.Get(options::kType, &windowType);
+ bool hiddenInMissionControl = false;
+ options.Get(options::kHiddenInMissionControl, &hiddenInMissionControl);
+
bool useStandardWindow = true;
// eventually deprecate separate "standardWindow" option in favor of
// standard / textured window types
@@ -347,6 +350,8 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
options.Get(options::kDisableAutoHideCursor, &disableAutoHideCursor);
[window_ setDisableAutoHideCursor:disableAutoHideCursor];
+ SetHiddenInMissionControl(hiddenInMissionControl);
+
// Set maximizable state last to ensure zoom button does not get reset
// by calls to other APIs.
SetMaximizable(maximizable);
@@ -1085,9 +1090,17 @@ bool NativeWindowMac::IsDocumentEdited() {
return [window_ isDocumentEdited];
}
+bool NativeWindowMac::IsHiddenInMissionControl() {
+ NSUInteger collectionBehavior = [window_ collectionBehavior];
+ return collectionBehavior & NSWindowCollectionBehaviorTransient;
+}
+
+void NativeWindowMac::SetHiddenInMissionControl(bool hidden) {
+ SetCollectionBehavior(hidden, NSWindowCollectionBehaviorTransient);
+}
+
void NativeWindowMac::SetIgnoreMouseEvents(bool ignore, bool forward) {
[window_ setIgnoresMouseEvents:ignore];
-
if (!ignore) {
SetForwardMouseMessages(NO);
} else {
diff --git a/shell/common/options_switches.cc b/shell/common/options_switches.cc
index 4a6bef3a694f..a50ea98c1e78 100644
--- a/shell/common/options_switches.cc
+++ b/shell/common/options_switches.cc
@@ -39,6 +39,8 @@ const char kOverlaySymbolColor[] = "symbolColor";
// The custom height for Window Controls Overlay.
const char kOverlayHeight[] = "height";
+// whether to keep the window out of mission control
+const char kHiddenInMissionControl[] = "hiddenInMissionControl";
// Whether the window should show in taskbar.
const char kSkipTaskbar[] = "skipTaskbar";
diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h
index 6c86d56799ac..46f966f879c5 100644
--- a/shell/common/options_switches.h
+++ b/shell/common/options_switches.h
@@ -30,6 +30,7 @@ extern const char kMinimizable[];
extern const char kMaximizable[];
extern const char kFullScreenable[];
extern const char kClosable[];
+extern const char kHiddenInMissionControl[];
extern const char kFullscreen[];
extern const char kSkipTaskbar[];
extern const char kKiosk[];
diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts
index 85fc5f229a49..68bb96c614c4 100644
--- a/spec/api-browser-window-spec.ts
+++ b/spec/api-browser-window-spec.ts
@@ -4784,6 +4784,24 @@ describe('BrowserWindow module', () => {
});
});
+ ifdescribe(process.platform === 'darwin')('isHiddenInMissionControl state', () => {
+ it('with functions', () => {
+ it('can be set with ignoreMissionControl constructor option', () => {
+ const w = new BrowserWindow({ show: false, hiddenInMissionControl: true });
+ expect(w.isHiddenInMissionControl()).to.be.true('isHiddenInMissionControl');
+ });
+
+ it('can be changed', () => {
+ const w = new BrowserWindow({ show: false });
+ expect(w.isHiddenInMissionControl()).to.be.false('isHiddenInMissionControl');
+ w.setHiddenInMissionControl(true);
+ expect(w.isHiddenInMissionControl()).to.be.true('isHiddenInMissionControl');
+ w.setHiddenInMissionControl(false);
+ expect(w.isHiddenInMissionControl()).to.be.false('isHiddenInMissionControl');
+ });
+ });
+ });
+
// fullscreen events are dispatched eagerly and twiddling things too fast can confuse poor Electron
ifdescribe(process.platform === 'darwin')('kiosk state', () => {